Merge branch 'kitty-kbd-event-types'

Related to #319
This commit is contained in:
Daniel Eklöf 2021-12-04 21:59:10 +01:00
commit a62e3cdb3d
No known key found for this signature in database
GPG key ID: 5BBD4992C116573F
3 changed files with 190 additions and 144 deletions

View file

@ -41,6 +41,9 @@
* `[mouse-bindings].selection-override-modifiers` option, specifying
which modifiers to hold to override mouse grabs by client
applications and force selection instead.
* Kitty keyboard protocol:
- [Report event types](https://sw.kovidgoyal.net/kitty/keyboard-protocol/#report-events)
(mode `0b10`)
### Changed
@ -58,7 +61,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.

153
input.c
View file

@ -1031,6 +1031,9 @@ static bool
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;
enum modifier keymap_mods = MOD_NONE;
keymap_mods |= seat->kbd.shift ? MOD_SHIFT : MOD_NONE;
keymap_mods |= seat->kbd.alt ? MOD_ALT : MOD_NONE;
@ -1145,6 +1148,25 @@ static bool
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 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;
if (!report_events && released)
return false;
if (composed && released)
return false;
/* TODO: should we even bother with this, or just say its not supported? */
if (!disambiguate && 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;
@ -1157,11 +1179,6 @@ kitty_kbd_protocol(struct seat *seat, struct terminal *term,
const uint8_t *const utf8 = ctx->utf8.buf;
const size_t count = ctx->utf8.count;
if (ctx->compose_status == XKB_COMPOSE_COMPOSED) {
term_to_slave(term, utf8, count);
return true;
}
if (effective == 0) {
switch (sym) {
case XKB_KEY_Return: term_to_slave(term, "\r", 1); return true;
@ -1170,16 +1187,10 @@ kitty_kbd_protocol(struct seat *seat, struct terminal *term,
}
}
/*
* 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 theres 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 (((iswprint(utf32) && (effective & ~caps_num) == 0) || composed)
&& !released)
{
term_to_slave(term, utf8, count);
return true;
}
@ -1301,31 +1312,23 @@ kitty_kbd_protocol(struct seat *seat, struct terminal *term,
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_Caps_Lock: if (false) {key = 57358; final = 'u';} break;
case XKB_KEY_Num_Lock: if (false) {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
default:
if (count > 0) {
if (effective == 0) {
term_to_slave(term, utf8, count);
return true;
}
case XKB_KEY_Shift_L: if (false) {key = 57441; final = 'u';} break;
case XKB_KEY_Control_L: if (false) {key = 57442; final = 'u';} break;
case XKB_KEY_Alt_L: if (false) {key = 57443; final = 'u';} break;
case XKB_KEY_Super_L: if (false) {key = 57444; final = 'u';} break;
case XKB_KEY_Hyper_L: if (false) {key = 57445; final = 'u';} break;
case XKB_KEY_Meta_L: if (false) {key = 57446; final = 'u';} break;
case XKB_KEY_Shift_R: if (false) {key = 57447; final = 'u';} break;
case XKB_KEY_Control_R: if (false) {key = 57448; final = 'u';} break;
case XKB_KEY_Alt_R: if (false) {key = 57449; final = 'u';} break;
case XKB_KEY_Super_R: if (false) {key = 57450; final = 'u';} break;
case XKB_KEY_Hyper_R: if (false) {key = 57451; final = 'u';} break;
case XKB_KEY_Meta_R: if (false) {key = 57452; final = 'u';} break;
default: {
/*
* Use keysym (typically its Unicode codepoint value).
*
@ -1378,16 +1381,40 @@ kitty_kbd_protocol(struct seat *seat, struct terminal *term,
}
}
key = use_level0_sym && ctx->level0_syms.count > 0
xkb_keysym_t sym_to_use = use_level0_sym && ctx->level0_syms.count > 0
? ctx->level0_syms.syms[0]
: sym;
final = 'u';
if (composed) {
wchar_t wc;
if (mbtowc(&wc, (const char *)utf8, count) == count) {
xassert(false);
key = wc;
}
}
if (key < 0) {
key = xkb_keysym_to_utf32(sym_to_use);
if (key == 0)
key = sym_to_use;
}
final = 'u';
break;
}
}
xassert(encoded_mods >= 1);
char event[4];
if (report_events) {
/* 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[16];
int bytes;
@ -1395,14 +1422,14 @@ kitty_kbd_protocol(struct seat *seat, struct terminal *term,
return false;
if (final == 'u' || final == '~') {
if (encoded_mods > 1)
bytes = snprintf(buf, sizeof(buf), "\x1b[%u;%u%c",
key, encoded_mods, final);
if (encoded_mods > 1 || event[0] != '\0')
bytes = snprintf(buf, sizeof(buf), "\x1b[%u;%u%s%c",
key, encoded_mods, event, final);
else
bytes = snprintf(buf, sizeof(buf), "\x1b[%u%c", key, final);
} else {
if (encoded_mods > 1)
bytes = snprintf(buf, sizeof(buf), "\x1b[1;%u%c", encoded_mods, final);
if (encoded_mods > 1 || event[0] != '\0')
bytes = snprintf(buf, sizeof(buf), "\x1b[1;%u%s%c", encoded_mods, event, final);
else
bytes = snprintf(buf, sizeof(buf), "\x1b[%c", final);
}
@ -1423,15 +1450,20 @@ key_press_release(struct seat *seat, struct terminal *term, uint32_t serial,
return;
}
if (state == XKB_KEY_UP) {
stop_repeater(seat, key);
return;
}
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);
bool should_repeat =
pressed && xkb_keymap_key_repeats(seat->kbd.xkb_keymap, key);
bool should_repeat = 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 &&
@ -1448,6 +1480,7 @@ key_press_release(struct seat *seat, struct terminal *term, uint32_t serial,
enum xkb_compose_status compose_status = XKB_COMPOSE_NOTHING;
if (seat->kbd.xkb_compose_state != NULL) {
if (pressed)
xkb_compose_state_feed(seat->kbd.xkb_compose_state, sym);
compose_status = xkb_compose_state_get_status(
seat->kbd.xkb_compose_state);
@ -1469,19 +1502,27 @@ key_press_release(struct seat *seat, struct terminal *term, uint32_t serial,
size_t raw_count = xkb_keymap_key_get_syms_by_level(
seat->kbd.xkb_keymap, key, layout_idx, 0, &raw_syms);
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);
seat, term, key, sym, bind_mods, bind_consumed,
raw_syms, raw_count, serial);
return;
} else if (urls_mode_is_active(term)) {
}
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);
seat, term, key, sym, bind_mods, bind_consumed,
raw_syms, raw_count, serial);
return;
}
}
#if 0
for (size_t i = 0; i < 32; i++) {
@ -1504,6 +1545,7 @@ key_press_release(struct seat *seat, struct terminal *term, uint32_t serial,
/*
* User configurable bindings
*/
if (pressed) {
tll_foreach(seat->kbd.bindings.key, it) {
const struct key_binding *bind = &it->item;
@ -1537,6 +1579,7 @@ key_press_release(struct seat *seat, struct terminal *term, uint32_t serial,
}
}
}
}
/*
* Keys generating escape sequences
@ -1595,7 +1638,7 @@ key_press_release(struct seat *seat, struct terminal *term, uint32_t serial,
? kitty_kbd_protocol(seat, term, &ctx)
: legacy_kbd_protocol(seat, term, &ctx);
if (seat->kbd.xkb_compose_state != NULL)
if (seat->kbd.xkb_compose_state != NULL && released)
xkb_compose_state_reset(seat->kbd.xkb_compose_state);
if (utf8 != buf)

View file

@ -133,7 +133,7 @@ enum kitty_kbd_flags {
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,
};
struct grid {