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.
WARNING: if you map <C-[> 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
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.
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
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|
#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.
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);
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);
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
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".
long sw;
char_u *s;
+ // May request the keyboard protocol state now.
+ may_send_t_RK();
+
if (ga_grow(&line_ga, 40) == FAIL)
break;
// 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)
"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.
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
// Re-enable bracketed paste mode and modifyOtherKeys
out_str(T_BE);
- out_str(T_CTI);
+ out_str_t_TI();
}
if (langmap_active)
if (tmode == TMODE_RAW)
// possibly enables modifyOtherKeys again
- out_str(T_CTI);
+ out_str_t_TI();
}
# endif
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);
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);
{(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"},
* 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
* 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_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 disabled modifyOtherKeys, because t_TI from xterm may already
+ // t_TE also disables modifyOtherKeys, because t_TI from xterm may already
// have been used.
{(int)KS_CTE, "\033[>4;m\033[=0;1u"},
{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"},
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).
{
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();
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
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)
#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
static int included_patches[] =
{ /* Add new patch number below this line */
+/**/
+ 980,
/**/
979,
/**/