# HG changeset patch # User Bram Moolenaar # Date 1669896903 -3600 # Node ID ff4473b3fc5814f5973139ae43daf5006a2acebb # Parent f319f620022021274e6afb2690b529c1712512ef patch 9.0.0980: the keyboard state response may end up in a shell command Commit: https://github.com/vim/vim/commit/733a69b29f0b0c3d2ddca463a41bdd912379bc5e Author: Bram Moolenaar Date: Thu Dec 1 12:03:47 2022 +0000 patch 9.0.0980: the keyboard state response may end up in a shell command Problem: The keyboard state response may end up in a shell command. Solution: Only request the keyboard protocol state when the typeahead is empty, no more commands are following and not exiting. Add the t_RK termcap entry for this. diff --git a/runtime/doc/map.txt b/runtime/doc/map.txt --- a/runtime/doc/map.txt +++ b/runtime/doc/map.txt @@ -1001,10 +1001,15 @@ mapping, see |map-bar|. WARNING: if you map you may very well break any key codes that start with Esc. Make sure it comes AFTER other mappings. -Vim automatically detects if the modifyOtherKeys mode was enabled when it -spots an escape sequence that must have been created by it. To see if Vim -detected such an escape sequence use `:verbose map`, the first line will then -show "Seen modifyOtherKeys: true" (possibly translated). +Starting with xterm version 377 Vim can detect the modifyOtherKeys state by +requesting it. For this the 't_RK' termcap entry is used. When the response +is found then Vim will know whether modifyOtherKeys level 2 is enabled, and +handle mappings accordingly. + +Before version 377 Vim automatically detects if the modifyOtherKeys mode was +enabled when it spots an escape sequence that must have been created by it. +To see if Vim detected such an escape sequence use `:verbose map`, the first +line will then show "Seen modifyOtherKeys: true" (possibly translated). This automatic detection depends on receiving an escape code starting with "<1b>[27;". This is the normal way xterm sends these key codes. However, if @@ -1016,6 +1021,9 @@ after the CTRL-V key. This can be used enabled: In Insert mode type CTRL-SHIFT-V CTRL-V, if you get one byte then modifyOtherKeys is off, if you get <1b>[27;5;118~ then it is on. +Note that xterm up to version 376 has a bug that makes Shift-Esc send a +regular Esc code, the Shift modifier is dropped. + When the 'esckeys' option is off, then modifyOtherKeys will be disabled in Insert mode to avoid every key with a modifier causing Insert mode to end. diff --git a/runtime/doc/term.txt b/runtime/doc/term.txt --- a/runtime/doc/term.txt +++ b/runtime/doc/term.txt @@ -90,6 +90,11 @@ Note: When 't_ti' is not empty, Vim assu alternate screen. This may slightly change what happens when executing a shell command or exiting Vim. To avoid this use 't_TI' and 't_TE'. +Vim will try to detect what keyboard protocol the terminal is using with the +'t_RK' termcap entry. This is sent after 't_TI', but only when there is no +work to do (no typeahead and no pending commands). That is to avoid the +response to end up in a shell command or arrive after Vim exits. + *xterm-bracketed-paste* When the 't_BE' option is set then 't_BE' will be sent to the terminal when entering "raw" mode and 't_BD' when leaving "raw" mode. The @@ -388,6 +393,8 @@ Added by Vim (there are no standard code xterm and other terminal emulators) The response is stored in |v:termresponse| |xterm-8bit| |'ttymouse'| |xterm-codes| + t_RK request terminal keyboard protocol state; *t_RK* *'t_RK'* + sent after |t_TI| t_u7 request cursor position (for xterm) *t_u7* *'t_u7'* see |'ambiwidth'| The response is stored in |v:termu7resp| diff --git a/src/edit.c b/src/edit.c --- a/src/edit.c +++ b/src/edit.c @@ -571,6 +571,8 @@ edit( #ifdef USE_ON_FLY_SCROLL dont_scroll = FALSE; // allow scrolling here #endif + // May request the keyboard protocol state now. + may_send_t_RK(); /* * Get a character for Insert mode. Ignore K_IGNORE and K_NOP. @@ -1479,7 +1481,8 @@ ins_redraw(int ready) // not busy wi aco_save_T aco; varnumber_T tick = CHANGEDTICK(curbuf); - // save and restore curwin and curbuf, in case the autocmd changes them + // Save and restore curwin and curbuf, in case the autocmd changes + // them. aucmd_prepbuf(&aco, curbuf); apply_autocmds(EVENT_TEXTCHANGEDI, NULL, NULL, FALSE, curbuf); aucmd_restbuf(&aco); @@ -1499,7 +1502,8 @@ ins_redraw(int ready) // not busy wi aco_save_T aco; varnumber_T tick = CHANGEDTICK(curbuf); - // save and restore curwin and curbuf, in case the autocmd changes them + // Save and restore curwin and curbuf, in case the autocmd changes + // them. aucmd_prepbuf(&aco, curbuf); apply_autocmds(EVENT_TEXTCHANGEDP, NULL, NULL, FALSE, curbuf); aucmd_restbuf(&aco); @@ -3706,7 +3710,7 @@ ins_esc( out_str(T_BE); // Re-enable modifyOtherKeys. - out_str(T_CTI); + out_str_t_TI(); } #ifdef FEAT_CONCEAL // Check if the cursor line needs redrawing after changing State. If @@ -4384,6 +4388,7 @@ bracketed_paste(paste_mode_T mode, int d do c = vgetc(); while (c == K_IGNORE || c == K_VER_SCROLLBAR || c == K_HOR_SCROLLBAR); + if (c == NUL || got_int || (ex_normal_busy > 0 && c == Ctrl_C)) // When CTRL-C was encountered the typeahead will be flushed and we // won't get the end sequence. Except when using ":normal". diff --git a/src/ex_getln.c b/src/ex_getln.c --- a/src/ex_getln.c +++ b/src/ex_getln.c @@ -2908,6 +2908,9 @@ getexmodeline( long sw; char_u *s; + // May request the keyboard protocol state now. + may_send_t_RK(); + if (ga_grow(&line_ga, 40) == FAIL) break; diff --git a/src/main.c b/src/main.c --- a/src/main.c +++ b/src/main.c @@ -1133,14 +1133,14 @@ may_trigger_safestateagain(void) // of calling feedkeys(), we check if it's now safe again (all keys // were consumed). was_safe = is_safe_now(); -#ifdef FEAT_EVAL +# ifdef FEAT_EVAL if (was_safe) ch_log(NULL, "SafeState: undo reset"); -#endif +# endif } if (was_safe) { -#ifdef FEAT_EVAL +# ifdef FEAT_EVAL // Only do this message when another message was given, otherwise we // get lots of them. if ((did_repeated_msg & REPEATED_MSG_SAFESTATE) == 0) @@ -1151,17 +1151,26 @@ may_trigger_safestateagain(void) "SafeState: back to waiting, triggering SafeStateAgain"); did_repeated_msg = did | REPEATED_MSG_SAFESTATE; } -#endif +# endif apply_autocmds(EVENT_SAFESTATEAGAIN, NULL, NULL, FALSE, curbuf); } -#ifdef FEAT_EVAL +# ifdef FEAT_EVAL else ch_log(NULL, "SafeState: back to waiting, not triggering SafeStateAgain"); -#endif +# endif } #endif +/* + * Return TRUE if there is any typeahead, pending operator or command. + */ + int +work_pending(void) +{ + return op_pending() || !is_safe_now(); +} + /* * Main loop: Execute Normal mode commands until exiting Vim. @@ -1477,10 +1486,11 @@ main_loop( gui_mouse_correct(); #endif - /* - * Update w_curswant if w_set_curswant has been set. - * Postponed until here to avoid computing w_virtcol too often. - */ + // May request the keyboard protocol state now. + may_send_t_RK(); + + // Update w_curswant if w_set_curswant has been set. + // Postponed until here to avoid computing w_virtcol too often. update_curswant(); #ifdef FEAT_EVAL diff --git a/src/normal.c b/src/normal.c --- a/src/normal.c +++ b/src/normal.c @@ -455,7 +455,7 @@ normal_cmd_get_more_chars( // Re-enable bracketed paste mode and modifyOtherKeys out_str(T_BE); - out_str(T_CTI); + out_str_t_TI(); } if (langmap_active) diff --git a/src/os_unix.c b/src/os_unix.c --- a/src/os_unix.c +++ b/src/os_unix.c @@ -5379,7 +5379,7 @@ finished: if (tmode == TMODE_RAW) // possibly enables modifyOtherKeys again - out_str(T_CTI); + out_str_t_TI(); } # endif diff --git a/src/proto/main.pro b/src/proto/main.pro --- a/src/proto/main.pro +++ b/src/proto/main.pro @@ -9,6 +9,7 @@ void may_trigger_safestate(int safe); void state_no_longer_safe(char *reason); int get_was_safe_state(void); void may_trigger_safestateagain(void); +int work_pending(void); void main_loop(int cmdwin, int noexmode); void getout_preserve_modified(int exitval); void getout(int exitval); diff --git a/src/proto/term.pro b/src/proto/term.pro --- a/src/proto/term.pro +++ b/src/proto/term.pro @@ -48,6 +48,8 @@ void shell_resized(void); void shell_resized_check(void); void set_shellsize(int width, int height, int mustset); void out_str_t_TE(void); +void out_str_t_TI(void); +void may_send_t_RK(void); void settmode(tmode_T tmode); void starttermcap(void); void stoptermcap(void); diff --git a/src/term.c b/src/term.c --- a/src/term.c +++ b/src/term.c @@ -452,7 +452,8 @@ static tcap_entry_T builtin_xterm[] = { {(int)KS_TI, "\0337\033[?47h"}, {(int)KS_TE, "\033[?47l\0338"}, # endif - {(int)KS_CTI, "\033[>4;2m\033[?4m"}, // see "builtin_mok2" + {(int)KS_CTI, "\033[>4;2m"}, + {(int)KS_CRK, "\033[?4m"}, // see "builtin_mok2" {(int)KS_CTE, "\033[>4;m"}, {(int)KS_CIS, "\033]1;"}, {(int)KS_CIE, "\007"}, @@ -593,10 +594,15 @@ static tcap_entry_T builtin_xterm[] = { * xterm. */ static tcap_entry_T builtin_mok2[] = { + // t_TI enables modifyOtherKeys level 2 + {(int)KS_CTI, "\033[>4;2m"}, + // XTQMODKEYS was added in xterm version 377: "CSI ? 4 m" which should // return "{lead} > 4 ; Pv m". Before version 377 we expect it to have no // effect. - {(int)KS_CTI, "\033[>4;2m\033[?4m"}, + {(int)KS_CRK, "\033[?4m"}, + + // t_TE disables modifyOtherKeys {(int)KS_CTE, "\033[>4;m"}, {(int)KS_NAME, NULL} // end marker @@ -606,11 +612,13 @@ static tcap_entry_T builtin_mok2[] = { * Additions for using the Kitty keyboard protocol. */ static tcap_entry_T builtin_kitty[] = { - // t_TI enables the kitty keyboard protocol, requests the kitty keyboard - // protocol state and requests the version response. - {(int)KS_CTI, "\033[=1;1u\033[?u\033[>c"}, - - // t_TE also disabled modifyOtherKeys, because t_TI from xterm may already + // t_TI enables the kitty keyboard protocol. + {(int)KS_CTI, "\033[=1;1u"}, + + // t_RK requests the kitty keyboard protocol state + {(int)KS_CRK, "\033[?u"}, + + // t_TE also disables modifyOtherKeys, because t_TI from xterm may already // have been used. {(int)KS_CTE, "\033[>4;m\033[=0;1u"}, @@ -1685,7 +1693,7 @@ get_term_entries(int *height, int *width {KS_CM, "cm"}, {KS_SR, "sr"}, {KS_CRI,"RI"}, {KS_VB, "vb"}, {KS_KS, "ks"}, {KS_KE, "ke"}, {KS_TI, "ti"}, {KS_TE, "te"}, - {KS_CTI, "TI"}, {KS_CTE, "TE"}, + {KS_CTI, "TI"}, {KS_CRK, "RK"}, {KS_CTE, "TE"}, {KS_BC, "bc"}, {KS_CSB,"Sb"}, {KS_CSF,"Sf"}, {KS_CAB,"AB"}, {KS_CAF,"AF"}, {KS_CAU,"AU"}, {KS_LE, "le"}, @@ -3693,6 +3701,40 @@ out_str_t_TE(void) kitty_protocol_state = KKPS_AFTER_T_KE; } +static int send_t_RK = FALSE; + +/* + * Output T_TI and setup for what follows. + */ + void +out_str_t_TI(void) +{ + out_str(T_CTI); + + // Send t_RK when there is no more work to do. + send_t_RK = TRUE; +} + +/* + * If t_TI was recently sent and there is no typeahead or work to do, now send + * t_RK. This is postponed to avoid the response arriving in a shell command + * or after Vim exits. + */ + void +may_send_t_RK(void) +{ + if (send_t_RK + && !work_pending() + && !ex_normal_busy + && !in_feedkeys + && !exiting) + { + send_t_RK = FALSE; + out_str(T_CRK); + out_flush(); + } +} + /* * Set the terminal to TMODE_RAW (for Normal mode) or TMODE_COOK (for external * commands and Ex mode). @@ -3751,7 +3793,7 @@ settmode(tmode_T tmode) { out_str(T_BE); // enable bracketed paste mode (should // be before mch_settmode(). - out_str(T_CTI); // possibly enables modifyOtherKeys + out_str_t_TI(); // possibly enables modifyOtherKeys } } out_flush(); @@ -3775,7 +3817,7 @@ starttermcap(void) MAY_WANT_TO_LOG_THIS; out_str(T_TI); // start termcap mode - out_str(T_CTI); // start "raw" mode + out_str_t_TI(); // start "raw" mode out_str(T_KS); // start "keypad transmit" mode out_str(T_BE); // enable bracketed paste mode diff --git a/src/termdefs.h b/src/termdefs.h --- a/src/termdefs.h +++ b/src/termdefs.h @@ -69,6 +69,7 @@ enum SpecialKey KS_KE, // out of "keypad transmit" mode KS_TI, // put terminal in termcap mode KS_CTI, // put terminal in "raw" mode + KS_CRK, // request keyboard protocol state KS_TE, // end of termcap mode KS_CTE, // end of "raw" mode KS_BC, // backspace character (cursor left) @@ -177,6 +178,7 @@ extern char_u *(term_strings[]); // c #define T_KE (TERM_STR(KS_KE)) // out of "keypad transmit" mode #define T_TI (TERM_STR(KS_TI)) // put terminal in termcap mode #define T_CTI (TERM_STR(KS_CTI)) // put terminal in "raw" mode +#define T_CRK (TERM_STR(KS_CRK)) // request keyboard protocol status #define T_TE (TERM_STR(KS_TE)) // end of termcap mode #define T_CTE (TERM_STR(KS_CTE)) // end of "raw" mode #define T_BC (TERM_STR(KS_BC)) // backspace character diff --git a/src/version.c b/src/version.c --- a/src/version.c +++ b/src/version.c @@ -696,6 +696,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 980, +/**/ 979, /**/ 978,