Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package foot for openSUSE:Factory checked in at 2021-12-09 19:45:41 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/foot (Old) and /work/SRC/openSUSE:Factory/.foot.new.2520 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "foot" Thu Dec 9 19:45:41 2021 rev:12 rq:937364 version:1.10.3 Changes: -------- --- /work/SRC/openSUSE:Factory/foot/foot.changes 2021-12-05 22:47:07.505443900 +0100 +++ /work/SRC/openSUSE:Factory/.foot.new.2520/foot.changes 2021-12-09 19:46:20.213154271 +0100 @@ -1,0 +2,8 @@ +Wed Dec 8 19:48:49 UTC 2021 - Arnav Singh <opens...@arnavion.dev> + +- Update to 1.10.3: + * Implemented support for all other modes of the Kitty keyboard protocol. + See Kitty keyboard protocol docs for more details. + * See https://codeberg.org/dnkl/foot/releases/tag/1.10.3 for more details. + +------------------------------------------------------------------- Old: ---- foot-1.10.2.tar.gz New: ---- foot-1.10.3.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ foot.spec ++++++ --- /var/tmp/diff_new_pack.S2QVNT/_old 2021-12-09 19:46:21.121154708 +0100 +++ /var/tmp/diff_new_pack.S2QVNT/_new 2021-12-09 19:46:21.125154710 +0100 @@ -17,7 +17,7 @@ Name: foot -Version: 1.10.2 +Version: 1.10.3 Release: 0 Summary: A Wayland terminal emulator License: MIT ++++++ foot-1.10.2.tar.gz -> foot-1.10.3.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/foot/CHANGELOG.md new/foot/CHANGELOG.md --- old/foot/CHANGELOG.md 2021-12-02 20:26:59.000000000 +0100 +++ new/foot/CHANGELOG.md 2021-12-08 18:09:50.000000000 +0100 @@ -1,5 +1,6 @@ # Changelog +* [1.10.3](#1-10-3) * [1.10.2](#1-10-2) * [1.10.1](#1-10-1) * [1.10.0](#1-10-0) @@ -34,6 +35,29 @@ * [1.2.0](#1-2-0) +## 1.10.3 + +### Added + +* Kitty keyboard protocol: + - [Report event types](https://sw.kovidgoyal.net/kitty/keyboard-protocol/#report-events) + (mode `0b10`) + - [Report alternate keys](https://sw.kovidgoyal.net/kitty/keyboard-protocol/#report-alternates) + (mode `0b100`, but not that only the _shifted_ key is reported, + not the _base layout key_) + - [Report all keys as escape codes](https://sw.kovidgoyal.net/kitty/keyboard-protocol/#report-all-keys) + (mode `0b1000`) + - [Report associated text](https://sw.kovidgoyal.net/kitty/keyboard-protocol/#report-text) + (mode `0b10000`) + + +### Fixed + +* Crash when bitmap fonts are scaled down to very small font sizes + (https://codeberg.org/dnkl/foot/issues/830). +* Crash when overwriting/erasing an OSC-8 URL. + + ## 1.10.2 ### Added @@ -41,7 +65,7 @@ * New value, `max`, for `[tweak].grapheme-width-method`. * Initial support for the [Kitty keyboard protocol](https://sw.kovidgoyal.net/kitty/keyboard-protocol/). Modes supported: - - [Disambiguate escape codes](https://sw.kovidgoyal.net/kitty/keyboard-protocol/#disambiguate) + - [Disambiguate escape codes](https://sw.kovidgoyal.net/kitty/keyboard-protocol/#disambiguate) (mode `0b1`) * ???Window menu??? (compositor provided) on right clicks on the CSD title bar. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/foot/INSTALL.md new/foot/INSTALL.md --- old/foot/INSTALL.md 2021-12-02 20:26:59.000000000 +0100 +++ new/foot/INSTALL.md 2021-12-08 18:09:50.000000000 +0100 @@ -39,6 +39,7 @@ ### Running +* UTF-8 locale * fontconfig * freetype * pixman @@ -449,19 +450,14 @@ ``` Where _???output-directory???_ **must** match the value passed to -`-Dcustom-terminfo-install-location` in the foot build. - -To compile and install directly (assuming the default -`-Dcustom-terminfo-install-location`): - -```sh -sudo tic -o /usr/share/foot/terminfo ... -``` +`-Dcustom-terminfo-install-location` in the foot build. If +`-Dcustom-terminfo-install-location` has not been set, `-o +<output-directoty>` can simply be omitted. Or, if packaging: ```sh -tic -o ${DESTDIR}/usr/share/foot/terminfo ... +tic -o ${DESTDIR}/usr/share/terminfo ... ``` diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/foot/grid.c new/foot/grid.c --- old/foot/grid.c 2021-12-02 20:26:59.000000000 +0100 +++ new/foot/grid.c 2021-12-08 18:09:50.000000000 +0100 @@ -69,10 +69,10 @@ } static void -uri_range_ensure_size(struct row_data *extra, size_t count_to_add) +uri_range_ensure_size(struct row_data *extra, uint32_t count_to_add) { if (extra->uri_ranges.count + count_to_add > extra->uri_ranges.size) { - extra->uri_ranges.size += count_to_add + count_to_add; + extra->uri_ranges.size = extra->uri_ranges.count + count_to_add; extra->uri_ranges.v = xrealloc( extra->uri_ranges.v, extra->uri_ranges.size * sizeof(extra->uri_ranges.v[0])); @@ -81,6 +81,10 @@ xassert(extra->uri_ranges.count + count_to_add <= extra->uri_ranges.size); } +/* + * Be careful! This function may xrealloc() the URI range vector, thus + * invalidating pointers into it. + */ static void uri_range_insert(struct row_data *extra, size_t idx, int start, int end, uint64_t id, const char *uri) @@ -1028,6 +1032,9 @@ uri_range_insert(extra, i + 1, col + 1, r->end, r->id, r->uri); + /* The insertion may xrealloc() the vector, making our + * ???old??? pointer invalid */ + r = &extra->uri_ranges.v[i]; r->end = col - 1; xassert(r->start <= r->end); @@ -1161,6 +1168,10 @@ /* Erase range erases a part in the middle of the URI */ uri_range_insert( extra, i + 1, end + 1, old->end, old->id, old->uri); + + /* The insertion may xrealloc() the vector, making our + * ???old??? pointer invalid */ + old = &extra->uri_ranges.v[i]; old->end = start - 1; return; /* There can be no more URIs affected by the erase range */ } @@ -1231,6 +1242,33 @@ verify_no_overlapping_uris(&row_data); verify_uris_are_sorted(&row_data); + grid_row_uri_range_destroy(&row_data.uri_ranges.v[0]); + grid_row_uri_range_destroy(&row_data.uri_ranges.v[1]); + row_data.uri_ranges.count = 0; + + /* + * Regression test: erasing the middle part of an URI causes us to + * insert a new URI (we split the partly erased URI into two). + * + * The insertion logic typically triggers an xrealloc(), which, in + * some cases, *moves* the entire URI vector to a new base + * address. grid_row_uri_range_erase() did not account for this, + * and tried to update the ???end??? member in the URI range we just + * split. This causes foot to crash when the xrealloc() has moved + * the URI range vector. + * + * (note: we???re only verifying we don???t crash here, hence the lack + * of assertions). + */ + free(row_data.uri_ranges.v); + row_data.uri_ranges.v = NULL; + row_data.uri_ranges.size = 0; + uri_range_append(&row_data, 1, 10, 0, "dummy"); + xassert(row_data.uri_ranges.size == 1); + + grid_row_uri_range_erase(&row, 5, 7); + xassert(row_data.uri_ranges.count == 2); + for (size_t i = 0; i < row_data.uri_ranges.count; i++) grid_row_uri_range_destroy(&row_data.uri_ranges.v[i]); free(row_data.uri_ranges.v); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/foot/input.c new/foot/input.c --- old/foot/input.c 2021-12-02 20:26:59.000000000 +0100 +++ new/foot/input.c 2021-12-08 18:09:50.000000000 +0100 @@ -1026,6 +1026,11 @@ legacy_kbd_protocol(struct seat *seat, struct terminal *term, const struct kbd_ctx *ctx) { + if (ctx->key_state != WL_KEYBOARD_KEY_STATE_PRESSED) + return false; + if (ctx->compose_status == XKB_COMPOSE_COMPOSING) + return false; + enum modifier keymap_mods = MOD_NONE; keymap_mods |= seat->kbd.shift ? MOD_SHIFT : MOD_NONE; keymap_mods |= seat->kbd.alt ? MOD_ALT : MOD_NONE; @@ -1140,6 +1145,30 @@ kitty_kbd_protocol(struct seat *seat, struct terminal *term, const struct kbd_ctx *ctx) { + const bool repeating = seat->kbd.repeat.dont_re_repeat; + const bool pressed = ctx->key_state == WL_KEYBOARD_KEY_STATE_PRESSED && !repeating; + const bool released = ctx->key_state == WL_KEYBOARD_KEY_STATE_RELEASED; + const bool composing = ctx->compose_status == XKB_COMPOSE_COMPOSING; + const bool composed = ctx->compose_status == XKB_COMPOSE_COMPOSED; + + const enum kitty_kbd_flags flags = + term->grid->kitty_kbd.flags[term->grid->kitty_kbd.idx]; + + const bool disambiguate = flags & KITTY_KBD_DISAMBIGUATE; + const bool report_events = flags & KITTY_KBD_REPORT_EVENT; + const bool report_alternate = flags & KITTY_KBD_REPORT_ALTERNATE; + const bool report_all_as_escapes = flags & KITTY_KBD_REPORT_ALL; + + if (!report_events && released) + return false; + + if (composed && released) + return false; + + /* TODO: should we even bother with this, or just say it???s not supported? */ + if (!disambiguate && !report_all_as_escapes && pressed) + return legacy_kbd_protocol(seat, term, ctx); + const xkb_mod_mask_t mods = ctx->mods & seat->kbd.kitty_significant; const xkb_mod_mask_t consumed = xkb_state_key_get_consumed_mods2( seat->kbd.xkb_state, ctx->key, XKB_CONSUMED_MODE_GTK) & seat->kbd.kitty_significant; @@ -1147,16 +1176,47 @@ const xkb_mod_mask_t caps_num = (seat->kbd.mod_caps != XKB_MOD_INVALID ? 1 << seat->kbd.mod_caps : 0) | (seat->kbd.mod_num != XKB_MOD_INVALID ? 1 << seat->kbd.mod_num : 0); + const xkb_keysym_t sym = ctx->sym; const uint32_t utf32 = ctx->utf32; const uint8_t *const utf8 = ctx->utf8.buf; + + const bool is_text = iswprint(utf32) && (effective & ~caps_num) == 0; const size_t count = ctx->utf8.count; - if (ctx->compose_status == XKB_COMPOSE_COMPOSED) { - term_to_slave(term, utf8, count); - return true; + const bool report_associated_text = + (flags & KITTY_KBD_REPORT_ASSOCIATED) && is_text && !released; + + if (composing) { + /* We never emit anything while composing, *except* modifiers + * (and only in report-all-keys-as-escape-codes mode) */ + switch (sym) { + case XKB_KEY_Caps_Lock: + case XKB_KEY_Num_Lock: + case XKB_KEY_Shift_L: + case XKB_KEY_Control_L: + case XKB_KEY_Alt_L: + case XKB_KEY_Super_L: + case XKB_KEY_Hyper_L: + case XKB_KEY_Meta_L: + case XKB_KEY_Shift_R: + case XKB_KEY_Control_R: + case XKB_KEY_Alt_R: + case XKB_KEY_Super_R: + case XKB_KEY_Hyper_R: + case XKB_KEY_Meta_R: + case XKB_KEY_ISO_Level3_Shift: + case XKB_KEY_ISO_Level5_Shift: + goto emit_escapes; + + default: + return false; + } } + if (report_all_as_escapes) + goto emit_escapes; + if (effective == 0) { switch (sym) { case XKB_KEY_Return: term_to_slave(term, "\r", 1); return true; @@ -1165,20 +1225,14 @@ } } - /* - * Printables without any modifiers are printed as is. - * - * TODO: plain text keys (a-z, 0-9 etc) are still printed as text, - * even when NumLock is active, despite NumLock being a - * significant modifier, *and* despite NumLock affecting other - * keys, like Return and Backspace; figure out if there???s some - * better magic than filtering out Caps- and Num-Lock here.. - */ - if (iswprint(utf32) && (effective & ~caps_num) == 0) { + /* Plain-text without modifiers, or commposed text, is emitted as-is */ + if (is_text && !released) { term_to_slave(term, utf8, count); return true; } +emit_escapes: + ; unsigned int encoded_mods = 0; if (seat->kbd.mod_shift != XKB_MOD_INVALID) encoded_mods |= mods & (1 << seat->kbd.mod_shift) ? (1 << 0) : 0; @@ -1194,7 +1248,7 @@ encoded_mods |= mods & (1 << seat->kbd.mod_num) ? (1 << 7) : 0; encoded_mods++; - int key = -1; + int key = -1, alternate = -1, base = -1; char final; switch (sym) { @@ -1296,113 +1350,172 @@ case XKB_KEY_XF86AudioRaiseVolume: key = 57439; final = 'u'; break; case XKB_KEY_XF86AudioMute: key = 57440; final = 'u'; break; -#if 0 /* TODO: enable when ???Report all keys as escape codes??? is enabled */ - case XKB_KEY_Caps_Lock: key = 57358; final = 'u'; break; - case XKB_KEY_Num_Lock: key = 57360; final = 'u'; break; - - case XKB_KEY_Shift_L: key = 57441; final = 'u'; break; - case XKB_KEY_Control_L: key = 57442; final = 'u'; break; - case XKB_KEY_Alt_L: key = 57443; final = 'u'; break; - case XKB_KEY_Super_L: key = 57444; final = 'u'; break; - case XKB_KEY_Hyper_L: key = 57445; final = 'u'; break; - case XKB_KEY_Meta_L: key = 57446; final = 'u'; break; - case XKB_KEY_Shift_R: key = 57447; final = 'u'; break; - case XKB_KEY_Control_R: key = 57448; final = 'u'; break; - case XKB_KEY_Alt_R: key = 57449; final = 'u'; break; - case XKB_KEY_Super_R: key = 57450; final = 'u'; break; - case XKB_KEY_Hyper_R: key = 57451; final = 'u'; break; - case XKB_KEY_Meta_R: key = 57452; final = 'u'; break; -#endif + case XKB_KEY_Caps_Lock: if (report_all_as_escapes) {key = 57358; final = 'u';} break; + case XKB_KEY_Num_Lock: if (report_all_as_escapes) {key = 57360; final = 'u';} break; - default: - if (count > 0) { - if (effective == 0) { - term_to_slave(term, utf8, count); - return true; - } + case XKB_KEY_Shift_L: if (report_all_as_escapes) {key = 57441; final = 'u';} break; + case XKB_KEY_Control_L: if (report_all_as_escapes) {key = 57442; final = 'u';} break; + case XKB_KEY_Alt_L: if (report_all_as_escapes) {key = 57443; final = 'u';} break; + case XKB_KEY_Super_L: if (report_all_as_escapes) {key = 57444; final = 'u';} break; + case XKB_KEY_Hyper_L: if (report_all_as_escapes) {key = 57445; final = 'u';} break; + case XKB_KEY_Meta_L: if (report_all_as_escapes) {key = 57446; final = 'u';} break; + case XKB_KEY_Shift_R: if (report_all_as_escapes) {key = 57447; final = 'u';} break; + case XKB_KEY_Control_R: if (report_all_as_escapes) {key = 57448; final = 'u';} break; + case XKB_KEY_Alt_R: if (report_all_as_escapes) {key = 57449; final = 'u';} break; + case XKB_KEY_Super_R: if (report_all_as_escapes) {key = 57450; final = 'u';} break; + case XKB_KEY_Hyper_R: if (report_all_as_escapes) {key = 57451; final = 'u';} break; + case XKB_KEY_Meta_R: if (report_all_as_escapes) {key = 57452; final = 'u';} break; + case XKB_KEY_ISO_Level3_Shift: if (report_all_as_escapes) {key = 57453; final = 'u';} break; + case XKB_KEY_ISO_Level5_Shift: if (report_all_as_escapes) {key = 57454; final = 'u';} break; - /* - * Use keysym (typically its Unicode codepoint value). - * - * If the keysym is shifted, use its unshifted codepoint - * instead. In other words, ctrl+a and ctrl+shift+a should - * both use the same value for ???key??? (97 - i.a. ???a???). - * - * However, if a non-significant modifier was used to - * generate the symbol. This is needed since we cannot - * encode non-significant modifiers, and thus the ???extra??? - * modifier(s) would get lost. - * - * Example: - * - * the Swedish layout has ???2???, QUOTATION MARK (???double - * quote???), ???@???, and ???????? on the same key. ???2??? is the base - * symbol. - * - * Shift+2 results in QUOTATION MARK - * AltGr+2 results in ???@??? - * AltGr+Shift+2 results in ???????? - * - * The kitty kbd protocol can???t encode AltGr. So, if we - * always used the base symbol (???2???), Alt+Shift+2 would - * result in the same escape sequence as - * AltGr+Alt+Shift+2. - * - * (yes, this matches what kitty does, as of 0.23.1) - */ - - /* Get the key???s shift level */ - xkb_level_index_t lvl = xkb_state_key_get_level( - seat->kbd.xkb_state, ctx->key, ctx->layout); - - /* And get all modifier combinations that, combined with - * the pressed key, results in the current shift level */ - xkb_mod_mask_t masks[32]; - size_t mask_count = xkb_keymap_key_get_mods_for_level( - seat->kbd.xkb_keymap, ctx->key, ctx->layout, lvl, - masks, ALEN(masks)); - - /* Check modifier combinations - if a combination has - * modifiers not in our set of ???significant??? modifiers, - * use key sym as-is */ - bool use_level0_sym = true; - for (size_t i = 0; i < mask_count; i++) { - if ((masks[i] & ~seat->kbd.kitty_significant) > 0) { - use_level0_sym = false; - break; - } + default: { + /* + * Use keysym (typically its Unicode codepoint value). + * + * If the keysym is shifted, use its unshifted codepoint + * instead. In other words, ctrl+a and ctrl+shift+a should + * both use the same value for ???key??? (97 - i.a. ???a???). + * + * However, if a non-significant modifier was used to + * generate the symbol. This is needed since we cannot + * encode non-significant modifiers, and thus the ???extra??? + * modifier(s) would get lost. + * + * Example: + * + * the Swedish layout has ???2???, QUOTATION MARK (???double + * quote???), ???@???, and ???????? on the same key. ???2??? is the base + * symbol. + * + * Shift+2 results in QUOTATION MARK + * AltGr+2 results in ???@??? + * AltGr+Shift+2 results in ???????? + * + * The kitty kbd protocol can???t encode AltGr. So, if we + * always used the base symbol (???2???), Alt+Shift+2 would + * result in the same escape sequence as + * AltGr+Alt+Shift+2. + * + * (yes, this matches what kitty does, as of 0.23.1) + */ + + /* Get the key???s shift level */ + xkb_level_index_t lvl = xkb_state_key_get_level( + seat->kbd.xkb_state, ctx->key, ctx->layout); + + /* And get all modifier combinations that, combined with + * the pressed key, results in the current shift level */ + xkb_mod_mask_t masks[32]; + size_t mask_count = xkb_keymap_key_get_mods_for_level( + seat->kbd.xkb_keymap, ctx->key, ctx->layout, lvl, + masks, ALEN(masks)); + + /* Check modifier combinations - if a combination has + * modifiers not in our set of ???significant??? modifiers, + * use key sym as-is */ + bool use_level0_sym = true; + for (size_t i = 0; i < mask_count; i++) { + if ((masks[i] & ~seat->kbd.kitty_significant) > 0) { + use_level0_sym = false; + break; } + } - key = use_level0_sym && ctx->level0_syms.count > 0 - ? ctx->level0_syms.syms[0] - : sym; - final = 'u'; + xkb_keysym_t sym_to_use = use_level0_sym && ctx->level0_syms.count > 0 + ? ctx->level0_syms.syms[0] + : sym; + + if (composed && is_text) + key = utf32; + else { + key = xkb_keysym_to_utf32(sym_to_use); + if (key == 0) + key = sym_to_use; + + /* The *shifted* key. May be the same as the unshifted + * key - if so, this is filtered out below, when + * emitting the CSI */ + alternate = xkb_keysym_to_utf32(sym); } + + /* Base layout key. I.e the symbol the pressed key produces in + * the base/default layout (layout idx 0) */ + const xkb_keysym_t *base_syms; + int base_sym_count = xkb_keymap_key_get_syms_by_level( + seat->kbd.xkb_keymap, ctx->key, 0, 0, &base_syms); + + if (base_sym_count > 0) + base = xkb_keysym_to_utf32(base_syms[0]); + + final = 'u'; break; } + } xassert(encoded_mods >= 1); - char buf[16]; - int bytes; + char event[4]; + if (report_events /*&& !pressed*/) { + /* Note: this deviates slightly from Kitty, which omits the + * ???:1??? subparameter for key press events */ + event[0] = ':'; + event[1] = '0' + (pressed ? 1 : repeating ? 2 : 3); + event[2] = '\0'; + } else + event[0] = '\0'; + + char buf[64], *p = buf; + size_t left = sizeof(buf); + size_t bytes; if (key < 0) return false; if (final == 'u' || final == '~') { - if (encoded_mods > 1) - bytes = snprintf(buf, sizeof(buf), "\x1b[%u;%u%c", - key, encoded_mods, final); - else - bytes = snprintf(buf, sizeof(buf), "\x1b[%u%c", key, final); + bytes = snprintf(p, left, "\x1b[%u", key); + p += bytes; left -= bytes; + + if (report_alternate) { + bool emit_alternate = alternate > 0 && alternate != key; + bool emit_base = base > 0 && base != key && base != alternate; + + if (emit_alternate) { + bytes = snprintf(p, left, ":%u", alternate); + p += bytes; left -= bytes; + } + + if (emit_base) { + bytes = snprintf( + p, left, "%s:%u", !emit_alternate ? ":" : "", base); + p += bytes; left -= bytes; + } + } + + bool emit_mods = encoded_mods > 1 || event[0] != '\0'; + + if (emit_mods) { + bytes = snprintf(p, left, ";%u%s", encoded_mods, event); + p += bytes; left -= bytes; + } + + if (report_associated_text) { + bytes = snprintf(p, left, "%s;%u", !emit_mods ? ";" : "", utf32); + p += bytes; left -= bytes; + } + + bytes = snprintf(p, left, "%c", final); + p += bytes; left -= bytes; } else { - if (encoded_mods > 1) - bytes = snprintf(buf, sizeof(buf), "\x1b[1;%u%c", encoded_mods, final); - else - bytes = snprintf(buf, sizeof(buf), "\x1b[%c", final); + if (encoded_mods > 1 || event[0] != '\0') { + bytes = snprintf(p, left, "\x1b[1;%u%s%c", encoded_mods, event, final); + p += bytes; left -= bytes; + } else { + bytes = snprintf(p, left, "\x1b[%c", final); + p += bytes; left -= bytes; + } } - term_to_slave(term, buf, bytes); + term_to_slave(term, buf, sizeof(buf) - left); return true; } @@ -1418,15 +1531,20 @@ return; } - if (state == XKB_KEY_UP) { + const bool pressed = state == WL_KEYBOARD_KEY_STATE_PRESSED; + //const bool repeated = pressed && seat->kbd.repeat.dont_re_repeat; + const bool released = state == WL_KEYBOARD_KEY_STATE_RELEASED; + + if (released) stop_repeater(seat, key); - return; - } - bool should_repeat = xkb_keymap_key_repeats(seat->kbd.xkb_keymap, key); + bool should_repeat = + pressed && xkb_keymap_key_repeats(seat->kbd.xkb_keymap, key); + xkb_keysym_t sym = xkb_state_key_get_one_sym(seat->kbd.xkb_state, key); - if (state == XKB_KEY_DOWN && term->conf->mouse.hide_when_typing && + if (pressed && term->conf->mouse.hide_when_typing && + /* TODO: better way to detect modifiers */ sym != XKB_KEY_Shift_L && sym != XKB_KEY_Shift_R && sym != XKB_KEY_Control_L && sym != XKB_KEY_Control_R && @@ -1443,13 +1561,13 @@ enum xkb_compose_status compose_status = XKB_COMPOSE_NOTHING; if (seat->kbd.xkb_compose_state != NULL) { - xkb_compose_state_feed(seat->kbd.xkb_compose_state, sym); + if (pressed) + xkb_compose_state_feed(seat->kbd.xkb_compose_state, sym); compose_status = xkb_compose_state_get_status( seat->kbd.xkb_compose_state); } - if (compose_status == XKB_COMPOSE_COMPOSING) - goto maybe_repeat; + const bool composed = compose_status == XKB_COMPOSE_COMPOSED; xkb_mod_mask_t mods, consumed; get_current_modifiers(seat, &mods, &consumed, key); @@ -1464,18 +1582,26 @@ 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 (should_repeat) - start_repeater(seat, key); - search_input( - seat, term, key, sym, bind_mods, bind_consumed, raw_syms, raw_count, serial); - return; - } else if (urls_mode_is_active(term)) { - if (should_repeat) - start_repeater(seat, key); - urls_input( - seat, term, key, sym, bind_mods, bind_consumed, raw_syms, raw_count, serial); - return; + if (pressed) { + if (term->is_searching) { + if (should_repeat) + start_repeater(seat, key); + + search_input( + seat, term, key, sym, bind_mods, bind_consumed, + raw_syms, raw_count, serial); + return; + } + + else if (urls_mode_is_active(term)) { + if (should_repeat) + start_repeater(seat, key); + + urls_input( + seat, term, key, sym, bind_mods, bind_consumed, + raw_syms, raw_count, serial); + return; + } } #if 0 @@ -1499,36 +1625,38 @@ /* * User configurable bindings */ - tll_foreach(seat->kbd.bindings.key, it) { - const struct key_binding *bind = &it->item; - - /* Match translated symbol */ - if (bind->sym == sym && - bind->mods == (bind_mods & ~bind_consumed) && - execute_binding( - seat, term, bind->action, bind->pipe_argv, serial)) - { - goto maybe_repeat; - } - - if (bind->mods != bind_mods) - continue; - - /* Match untranslated symbols */ - for (size_t i = 0; i < raw_count; i++) { - if (bind->sym == raw_syms[i] && execute_binding( + if (pressed) { + tll_foreach(seat->kbd.bindings.key, it) { + const struct key_binding *bind = &it->item; + + /* Match translated symbol */ + if (bind->sym == sym && + bind->mods == (bind_mods & ~bind_consumed) && + execute_binding( seat, term, bind->action, bind->pipe_argv, serial)) { goto maybe_repeat; } - } - /* Match raw key code */ - tll_foreach(bind->key_codes, code) { - if (code->item == key && execute_binding( - seat, term, bind->action, bind->pipe_argv, serial)) - { - goto maybe_repeat; + if (bind->mods != bind_mods) + continue; + + /* Match untranslated symbols */ + for (size_t i = 0; i < raw_count; i++) { + if (bind->sym == raw_syms[i] && execute_binding( + seat, term, bind->action, bind->pipe_argv, serial)) + { + goto maybe_repeat; + } + } + + /* Match raw key code */ + tll_foreach(bind->key_codes, code) { + if (code->item == key && execute_binding( + seat, term, bind->action, bind->pipe_argv, serial)) + { + goto maybe_repeat; + } } } } @@ -1542,13 +1670,12 @@ * Compose, and maybe emit "normal" character */ - xassert(seat->kbd.xkb_compose_state != NULL || - compose_status != XKB_COMPOSE_COMPOSED); + xassert(seat->kbd.xkb_compose_state != NULL || !composed); if (compose_status == XKB_COMPOSE_CANCELLED) goto maybe_repeat; - int count = compose_status == XKB_COMPOSE_COMPOSED + int count = 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); @@ -1558,9 +1685,13 @@ uint8_t *utf8 = count < sizeof(buf) ? buf : xmalloc(count + 1); uint32_t utf32 = (uint32_t)-1; - if (compose_status == XKB_COMPOSE_COMPOSED) { + if (composed) { xkb_compose_state_get_utf8( seat->kbd.xkb_compose_state, (char *)utf8, count + 1); + + wchar_t wc; + if (mbtowc(&wc, (const char *)utf8, count) == count) + utf32 = wc; } else { xkb_state_key_get_utf8( seat->kbd.xkb_state, key, (char *)utf8, count + 1); @@ -1590,7 +1721,7 @@ ? kitty_kbd_protocol(seat, term, &ctx) : legacy_kbd_protocol(seat, term, &ctx); - if (seat->kbd.xkb_compose_state != NULL) + if (composed && released) xkb_compose_state_reset(seat->kbd.xkb_compose_state); if (utf8 != buf) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/foot/meson.build new/foot/meson.build --- old/foot/meson.build 2021-12-02 20:26:59.000000000 +0100 +++ new/foot/meson.build 2021-12-08 18:09:50.000000000 +0100 @@ -1,5 +1,5 @@ project('foot', 'c', - version: '1.10.2', + version: '1.10.3', license: 'MIT', meson_version: '>=0.54.0', default_options: [ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/foot/terminal.c new/foot/terminal.c --- old/foot/terminal.c 2021-12-02 20:26:59.000000000 +0100 +++ new/foot/terminal.c 2021-12-08 18:09:50.000000000 +0100 @@ -688,6 +688,11 @@ : max(term->fonts[0]->height, term->fonts[0]->ascent + term->fonts[0]->descent); + if (term->cell_width <= 0) + term->cell_width = 1; + if (term->cell_height <= 0) + term->cell_height = 1; + term->font_x_ofs = term_pt_or_px_as_pixels(term, &conf->horizontal_letter_offset); term->font_y_ofs = term_pt_or_px_as_pixels(term, &conf->vertical_letter_offset); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/foot/terminal.h new/foot/terminal.h --- old/foot/terminal.h 2021-12-02 20:26:59.000000000 +0100 +++ new/foot/terminal.h 2021-12-08 18:09:50.000000000 +0100 @@ -133,7 +133,11 @@ KITTY_KBD_REPORT_ALTERNATE = 0x04, KITTY_KBD_REPORT_ALL = 0x08, KITTY_KBD_REPORT_ASSOCIATED = 0x10, - KITTY_KBD_SUPPORTED = KITTY_KBD_DISAMBIGUATE, + KITTY_KBD_SUPPORTED = (KITTY_KBD_DISAMBIGUATE | + KITTY_KBD_REPORT_EVENT | + KITTY_KBD_REPORT_ALTERNATE | + KITTY_KBD_REPORT_ALL | + KITTY_KBD_REPORT_ASSOCIATED), }; struct grid {