diff --git a/CHANGELOG.md b/CHANGELOG.md index 4381b883..9c03555d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -46,6 +46,7 @@ * Color schemes are now installed to `${datadir}/foot/themes`. * `[csd].border-width` and `[csd].border-color`, allowing you to configure the width and color of the CSD border. +* Support for `XTMODKEYS` with `Pp=4` and `Pv=2` (_modifyOtherKeys=2_). ### Changed diff --git a/csi.c b/csi.c index 4a9658f3..becfc142 100644 --- a/csi.c +++ b/csi.c @@ -1509,19 +1509,21 @@ csi_dispatch(struct terminal *term, uint8_t final) case 1: /* modifyCursorKeys */ case 2: /* modifyFunctionKeys */ - case 4: /* modifyOtherKeys */ /* Ignored, we always report modifiers */ - if (value != 2 && value != -1 && - !(resource == 4 && value == 1)) - { - LOG_WARN("unimplemented: %s = %d", - resource == 1 ? "modifyCursorKeys" : - resource == 2 ? "modifyFunctionKeys" : - resource == 4 ? "modifyOtherKeys" : "", - value); + if (value != 2 && value != -1) { + LOG_WARN( + "unimplemented: %s = %d", + resource == 1 ? "modifyCursorKeys" : + resource == 2 ? "modifyFunctionKeys" : "", + value); } break; + case 4: /* modifyOtherKeys */ + term->modify_other_keys_2 = value == 2; + LOG_DBG("modifyOtherKeys=%d", value); + break; + default: LOG_WARN("invalid resource %d in %s", resource, csi_as_string(term, final, -1)); diff --git a/input.c b/input.c index 1428deda..0aef43cc 100644 --- a/input.c +++ b/input.c @@ -901,7 +901,20 @@ keymap_lookup(struct terminal *term, xkb_keysym_t sym, enum modifier mods) LOG_DBG("keypad mode: %d", keypad_keys_mode); for (size_t j = 0; j < count; j++) { - if (info[j].modifiers != MOD_ANY && info[j].modifiers != mods) + enum modifier modifiers = info[j].modifiers; + + if (modifiers & MOD_MODIFY_OTHER_KEYS_STATE1) { + if (term->modify_other_keys_2) + continue; + modifiers &= ~MOD_MODIFY_OTHER_KEYS_STATE1; + } + if (modifiers & MOD_MODIFY_OTHER_KEYS_STATE2) { + if (!term->modify_other_keys_2) + continue; + modifiers &= ~MOD_MODIFY_OTHER_KEYS_STATE2; + } + + if (modifiers != MOD_ANY && modifiers != mods) continue; if (info[j].cursor_keys_mode != CURSOR_KEYS_DONTCARE && @@ -927,9 +940,26 @@ UNITTEST }; const struct key_data *info = keymap_lookup(&term, XKB_KEY_ISO_Left_Tab, MOD_SHIFT | MOD_CTRL); + xassert(info != NULL); xassert(strcmp(info->seq, "\033[27;6;9~") == 0); } +UNITTEST +{ + struct terminal term = { + .modify_other_keys_2 = false, + }; + + const struct key_data *info = keymap_lookup(&term, XKB_KEY_Return, MOD_ALT); + xassert(info != NULL); + xassert(strcmp(info->seq, "\033\r") == 0); + + term.modify_other_keys_2 = true; + info = keymap_lookup(&term, XKB_KEY_Return, MOD_ALT); + xassert(info != NULL); + xassert(strcmp(info->seq, "\033[27;3;13~") == 0); +} + static void get_current_modifiers(const struct seat *seat, xkb_mod_mask_t *effective, @@ -1139,10 +1169,14 @@ key_press_release(struct seat *seat, struct terminal *term, uint32_t serial, #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(utf8[0])) && - sym < 256) + LOG_DBG("term->modify_other_keys=%d, count=%d, is_ctrl=%d (utf8=0x%02x), sym=%d", + term->modify_other_keys_2, count, IS_CTRL(utf8[0]), utf8[0], sym); + + bool ctrl_is_in_effect = (keymap_mods & MOD_CTRL) != 0; + bool ctrl_seq = is_control_key(sym) || (count == 1 && IS_CTRL(utf8[0])); + + if (keymap_mods != MOD_NONE && (term->modify_other_keys_2 || + (ctrl_is_in_effect && !ctrl_seq))) { static const int mod_param_map[32] = { [MOD_SHIFT] = 2, diff --git a/keymap.h b/keymap.h index f98647c3..6b882391 100644 --- a/keymap.h +++ b/keymap.h @@ -11,6 +11,8 @@ enum modifier { MOD_ALT = 0x4, MOD_CTRL = 0x8, MOD_META = 0x10, + MOD_MODIFY_OTHER_KEYS_STATE1 = 0x20, + MOD_MODIFY_OTHER_KEYS_STATE2 = 0x40, }; struct key_data { @@ -41,7 +43,8 @@ static const struct key_data key_escape[] = { static const struct key_data key_return[] = { {MOD_SHIFT, CURSOR_KEYS_DONTCARE, KEYPAD_DONTCARE, "\033[27;2;13~"}, - {MOD_ALT, CURSOR_KEYS_DONTCARE, KEYPAD_DONTCARE, "\033\r"}, + {MOD_ALT | MOD_MODIFY_OTHER_KEYS_STATE1, CURSOR_KEYS_DONTCARE, KEYPAD_DONTCARE, "\033\r"}, + {MOD_ALT | MOD_MODIFY_OTHER_KEYS_STATE2, CURSOR_KEYS_DONTCARE, KEYPAD_DONTCARE, "\033[27;3;13~"}, {MOD_SHIFT | MOD_ALT, CURSOR_KEYS_DONTCARE, KEYPAD_DONTCARE, "\033[27;4;13~"}, {MOD_CTRL, CURSOR_KEYS_DONTCARE, KEYPAD_DONTCARE, "\033[27;5;13~"}, {MOD_SHIFT | MOD_CTRL, CURSOR_KEYS_DONTCARE, KEYPAD_DONTCARE, "\033[27;6;13~"}, @@ -60,7 +63,8 @@ static const struct key_data key_return[] = { /* Tab isn't covered by the regular "modifyOtherKeys" handling */ static const struct key_data key_tab[] = { - {MOD_SHIFT, CURSOR_KEYS_DONTCARE, KEYPAD_DONTCARE, "\033[Z"}, + {MOD_SHIFT | MOD_MODIFY_OTHER_KEYS_STATE1, CURSOR_KEYS_DONTCARE, KEYPAD_DONTCARE, "\033[Z"}, + {MOD_SHIFT | MOD_MODIFY_OTHER_KEYS_STATE2, CURSOR_KEYS_DONTCARE, KEYPAD_DONTCARE, "\033[27;2;9~"}, {MOD_ALT, CURSOR_KEYS_DONTCARE, KEYPAD_DONTCARE, "\033[27;3;9~"}, {MOD_SHIFT | MOD_ALT, CURSOR_KEYS_DONTCARE, KEYPAD_DONTCARE, "\033[27;4;9~"}, {MOD_CTRL, CURSOR_KEYS_DONTCARE, KEYPAD_DONTCARE, "\033[27;5;9~"}, @@ -96,22 +100,38 @@ static const struct key_data key_iso_left_tab[] = { }; static const struct key_data key_backspace[] = { - {MOD_SHIFT, CURSOR_KEYS_DONTCARE, KEYPAD_DONTCARE, "\x7f"}, - {MOD_ALT, CURSOR_KEYS_DONTCARE, KEYPAD_DONTCARE, "\033\x7f"}, - {MOD_SHIFT | MOD_ALT, CURSOR_KEYS_DONTCARE, KEYPAD_DONTCARE, "\033\x7f"}, - {MOD_CTRL, CURSOR_KEYS_DONTCARE, KEYPAD_DONTCARE, "\x08"}, - {MOD_SHIFT | MOD_CTRL, CURSOR_KEYS_DONTCARE, KEYPAD_DONTCARE, "\x08"}, - {MOD_ALT | MOD_CTRL, CURSOR_KEYS_DONTCARE, KEYPAD_DONTCARE, "\033\x08"}, - {MOD_SHIFT | MOD_ALT | MOD_CTRL, CURSOR_KEYS_DONTCARE, KEYPAD_DONTCARE, "\033\x08"}, - {MOD_META, CURSOR_KEYS_DONTCARE, KEYPAD_DONTCARE, "\x7f"}, - {MOD_META | MOD_SHIFT, CURSOR_KEYS_DONTCARE, KEYPAD_DONTCARE, "\x7f"}, - {MOD_META | MOD_ALT, CURSOR_KEYS_DONTCARE, KEYPAD_DONTCARE, "\033\x7f"}, - {MOD_META | MOD_SHIFT | MOD_ALT, CURSOR_KEYS_DONTCARE, KEYPAD_DONTCARE, "\033\x7f"}, - {MOD_META | MOD_CTRL, CURSOR_KEYS_DONTCARE, KEYPAD_DONTCARE, "\x08"}, - {MOD_META | MOD_SHIFT | MOD_CTRL, CURSOR_KEYS_DONTCARE, KEYPAD_DONTCARE, "\x08"}, - {MOD_META | MOD_ALT | MOD_CTRL, CURSOR_KEYS_DONTCARE, KEYPAD_DONTCARE, "\033\x08"}, - {MOD_META | MOD_SHIFT | MOD_ALT | MOD_CTRL, CURSOR_KEYS_DONTCARE, KEYPAD_DONTCARE, "\033\x08"}, - {MOD_ANY, CURSOR_KEYS_DONTCARE, KEYPAD_DONTCARE, "\x7f"}, + {MOD_SHIFT | MOD_MODIFY_OTHER_KEYS_STATE1, CURSOR_KEYS_DONTCARE, KEYPAD_DONTCARE, "\x7f"}, + {MOD_ALT | MOD_MODIFY_OTHER_KEYS_STATE1, CURSOR_KEYS_DONTCARE, KEYPAD_DONTCARE, "\033\x7f"}, + {MOD_SHIFT | MOD_ALT | MOD_MODIFY_OTHER_KEYS_STATE1, CURSOR_KEYS_DONTCARE, KEYPAD_DONTCARE, "\033\x7f"}, + {MOD_SHIFT | MOD_CTRL | MOD_MODIFY_OTHER_KEYS_STATE1, CURSOR_KEYS_DONTCARE, KEYPAD_DONTCARE, "\x08"}, + {MOD_ALT | MOD_CTRL | MOD_MODIFY_OTHER_KEYS_STATE1, CURSOR_KEYS_DONTCARE, KEYPAD_DONTCARE, "\033\x08"}, + {MOD_SHIFT | MOD_ALT | MOD_CTRL | MOD_MODIFY_OTHER_KEYS_STATE1, CURSOR_KEYS_DONTCARE, KEYPAD_DONTCARE, "\033\x08"}, + {MOD_META | MOD_MODIFY_OTHER_KEYS_STATE1, CURSOR_KEYS_DONTCARE, KEYPAD_DONTCARE, "\x7f"}, + {MOD_META | MOD_SHIFT | MOD_MODIFY_OTHER_KEYS_STATE1, CURSOR_KEYS_DONTCARE, KEYPAD_DONTCARE, "\x7f"}, + {MOD_META | MOD_ALT | MOD_MODIFY_OTHER_KEYS_STATE1, CURSOR_KEYS_DONTCARE, KEYPAD_DONTCARE, "\033\x7f"}, + {MOD_META | MOD_SHIFT | MOD_ALT | MOD_MODIFY_OTHER_KEYS_STATE1, CURSOR_KEYS_DONTCARE, KEYPAD_DONTCARE, "\033\x7f"}, + {MOD_META | MOD_CTRL | MOD_MODIFY_OTHER_KEYS_STATE1, CURSOR_KEYS_DONTCARE, KEYPAD_DONTCARE, "\x08"}, + {MOD_META | MOD_SHIFT | MOD_CTRL | MOD_MODIFY_OTHER_KEYS_STATE1, CURSOR_KEYS_DONTCARE, KEYPAD_DONTCARE, "\x08"}, + {MOD_META | MOD_ALT | MOD_CTRL | MOD_MODIFY_OTHER_KEYS_STATE1, CURSOR_KEYS_DONTCARE, KEYPAD_DONTCARE, "\033\x08"}, + {MOD_META | MOD_SHIFT | MOD_ALT | MOD_CTRL | MOD_MODIFY_OTHER_KEYS_STATE1, CURSOR_KEYS_DONTCARE, KEYPAD_DONTCARE, "\033\x08"}, + + {MOD_SHIFT | MOD_MODIFY_OTHER_KEYS_STATE2, CURSOR_KEYS_DONTCARE, KEYPAD_DONTCARE, "\033[27;2;127~"}, + {MOD_ALT | MOD_MODIFY_OTHER_KEYS_STATE2, CURSOR_KEYS_DONTCARE, KEYPAD_DONTCARE, "\033[27;3;127~"}, + {MOD_SHIFT | MOD_ALT | MOD_MODIFY_OTHER_KEYS_STATE2, CURSOR_KEYS_DONTCARE, KEYPAD_DONTCARE, "\033[27;4;127~"}, + {MOD_SHIFT | MOD_CTRL | MOD_MODIFY_OTHER_KEYS_STATE2, CURSOR_KEYS_DONTCARE, KEYPAD_DONTCARE, "\033[27;6;8~"}, + {MOD_ALT | MOD_CTRL | MOD_MODIFY_OTHER_KEYS_STATE2, CURSOR_KEYS_DONTCARE, KEYPAD_DONTCARE, "\033[27;7;8~"}, + {MOD_SHIFT | MOD_ALT | MOD_CTRL | MOD_MODIFY_OTHER_KEYS_STATE2, CURSOR_KEYS_DONTCARE, KEYPAD_DONTCARE, "\033[27;8;8~"}, + {MOD_META | MOD_MODIFY_OTHER_KEYS_STATE2, CURSOR_KEYS_DONTCARE, KEYPAD_DONTCARE, "\033[27;9;127~"}, + {MOD_META | MOD_SHIFT | MOD_MODIFY_OTHER_KEYS_STATE2, CURSOR_KEYS_DONTCARE, KEYPAD_DONTCARE, "\033[27;10;127~"}, + {MOD_META | MOD_ALT | MOD_MODIFY_OTHER_KEYS_STATE2, CURSOR_KEYS_DONTCARE, KEYPAD_DONTCARE, "\033[27;11;127~"}, + {MOD_META | MOD_SHIFT | MOD_ALT | MOD_MODIFY_OTHER_KEYS_STATE2, CURSOR_KEYS_DONTCARE, KEYPAD_DONTCARE, "\033[27;12;127~"}, + {MOD_META | MOD_CTRL | MOD_MODIFY_OTHER_KEYS_STATE2, CURSOR_KEYS_DONTCARE, KEYPAD_DONTCARE, "\033[27;13;8~"}, + {MOD_META | MOD_SHIFT | MOD_CTRL | MOD_MODIFY_OTHER_KEYS_STATE2, CURSOR_KEYS_DONTCARE, KEYPAD_DONTCARE, "\033[27;14;8~"}, + {MOD_META | MOD_ALT | MOD_CTRL | MOD_MODIFY_OTHER_KEYS_STATE2, CURSOR_KEYS_DONTCARE, KEYPAD_DONTCARE, "\033[27;15;8~"}, + {MOD_META | MOD_SHIFT | MOD_ALT | MOD_CTRL | MOD_MODIFY_OTHER_KEYS_STATE2, CURSOR_KEYS_DONTCARE, KEYPAD_DONTCARE, "\033[27;16;8~"}, + + {MOD_CTRL, CURSOR_KEYS_DONTCARE, KEYPAD_DONTCARE, "\x08"}, + {MOD_ANY, CURSOR_KEYS_DONTCARE, KEYPAD_DONTCARE, "\x7f"}, }; #define DEFAULT_MODS_FOR_SINGLE(sym) \ diff --git a/terminal.h b/terminal.h index 10be6ae3..3516551f 100644 --- a/terminal.h +++ b/terminal.h @@ -308,6 +308,7 @@ struct terminal { bool focus_events; bool alt_scrolling; bool modify_escape_key; + bool modify_other_keys_2; /* True when modifyOtherKeys=2 (i.e. “CSI >4;2m”) */ enum cursor_origin origin; enum cursor_keys cursor_keys_mode; enum keypad_keys keypad_keys_mode;