Mercurial > vim
comparison src/term.c @ 31303:d2107f7b2155 v9.0.0985
patch 9.0.0985: when using kitty keyboard protocol function keys may not work
Commit: https://github.com/vim/vim/commit/1a173409ae6a39d59ff99cf3d567c25e859f9ecd
Author: Bram Moolenaar <Bram@vim.org>
Date: Fri Dec 2 12:28:47 2022 +0000
patch 9.0.0985: when using kitty keyboard protocol function keys may not work
Problem: When using kitty keyboard protocol function keys may not work.
(Kovid Goyal)
Solution: Recognize CSI ending in [ABCDEFHPQRS] also when the termcap
entries are not specified. (closes #11648)
author | Bram Moolenaar <Bram@vim.org> |
---|---|
date | Fri, 02 Dec 2022 13:30:04 +0100 |
parents | 311e11e63356 |
children | 216c01bb1f90 |
comparison
equal
deleted
inserted
replaced
31302:b55781a559df | 31303:d2107f7b2155 |
---|---|
2046 gui_init(); | 2046 gui_init(); |
2047 // If starting the GUI failed, don't do any of the other | 2047 // If starting the GUI failed, don't do any of the other |
2048 // things for this terminal | 2048 // things for this terminal |
2049 if (!gui.in_use) | 2049 if (!gui.in_use) |
2050 return FAIL; | 2050 return FAIL; |
2051 #ifdef HAVE_TGETENT | 2051 # ifdef HAVE_TGETENT |
2052 break; // don't try using external termcap | 2052 break; // don't try using external termcap |
2053 #endif | 2053 # endif |
2054 } | 2054 } |
2055 #endif // FEAT_GUI | 2055 #endif // FEAT_GUI |
2056 } | 2056 } |
2057 #ifdef HAVE_TGETENT | 2057 #ifdef HAVE_TGETENT |
2058 } | 2058 } |
5086 buf[idx++] = key; | 5086 buf[idx++] = key; |
5087 return idx; | 5087 return idx; |
5088 } | 5088 } |
5089 | 5089 |
5090 /* | 5090 /* |
5091 * Shared between handle_key_with_modifier() and handle_csi_function_key(). | |
5092 */ | |
5093 static int | |
5094 put_key_modifiers_in_typebuf( | |
5095 int key_arg, | |
5096 int modifiers_arg, | |
5097 int csi_len, | |
5098 int offset, | |
5099 char_u *buf, | |
5100 int bufsize, | |
5101 int *buflen) | |
5102 { | |
5103 int key = key_arg; | |
5104 int modifiers = modifiers_arg; | |
5105 | |
5106 // Some keys need adjustment when the Ctrl modifier is used. | |
5107 key = may_adjust_key_for_ctrl(modifiers, key); | |
5108 | |
5109 // May remove the shift modifier if it's already included in the key. | |
5110 modifiers = may_remove_shift_modifier(modifiers, key); | |
5111 | |
5112 // Produce modifiers with K_SPECIAL KS_MODIFIER {mod} | |
5113 char_u string[MAX_KEY_CODE_LEN + 1]; | |
5114 int new_slen = modifiers2keycode(modifiers, &key, string); | |
5115 | |
5116 // Add the bytes for the key. | |
5117 new_slen += add_key_to_buf(key, string + new_slen); | |
5118 | |
5119 string[new_slen] = NUL; | |
5120 if (put_string_in_typebuf(offset, csi_len, string, new_slen, | |
5121 buf, bufsize, buflen) == FAIL) | |
5122 return -1; | |
5123 return new_slen - csi_len + offset; | |
5124 } | |
5125 | |
5126 /* | |
5091 * Handle a sequence with key and modifier, one of: | 5127 * Handle a sequence with key and modifier, one of: |
5092 * {lead}27;{modifier};{key}~ | 5128 * {lead}27;{modifier};{key}~ |
5093 * {lead}{key};{modifier}u | 5129 * {lead}{key};{modifier}u |
5094 * Returns the difference in length. | 5130 * Returns the difference in length. |
5095 */ | 5131 */ |
5101 int offset, | 5137 int offset, |
5102 char_u *buf, | 5138 char_u *buf, |
5103 int bufsize, | 5139 int bufsize, |
5104 int *buflen) | 5140 int *buflen) |
5105 { | 5141 { |
5106 int key; | |
5107 int modifiers; | |
5108 char_u string[MAX_KEY_CODE_LEN + 1]; | |
5109 | |
5110 // Only set seenModifyOtherKeys for the "{lead}27;" code to avoid setting | 5142 // Only set seenModifyOtherKeys for the "{lead}27;" code to avoid setting |
5111 // it for terminals using the kitty keyboard protocol. Xterm sends | 5143 // it for terminals using the kitty keyboard protocol. Xterm sends |
5112 // the form ending in "u" when the formatOtherKeys resource is set. We do | 5144 // the form ending in "u" when the formatOtherKeys resource is set. We do |
5113 // not support this. | 5145 // not support this. |
5114 // | 5146 // |
5121 if (trail != 'u' | 5153 if (trail != 'u' |
5122 && (kitty_protocol_state == KKPS_INITIAL | 5154 && (kitty_protocol_state == KKPS_INITIAL |
5123 || kitty_protocol_state == KKPS_OFF | 5155 || kitty_protocol_state == KKPS_OFF |
5124 || kitty_protocol_state == KKPS_AFTER_T_KE) | 5156 || kitty_protocol_state == KKPS_AFTER_T_KE) |
5125 && term_props[TPR_KITTY].tpr_status != TPR_YES) | 5157 && term_props[TPR_KITTY].tpr_status != TPR_YES) |
5158 { | |
5159 ch_log(NULL, "setting seenModifyOtherKeys to TRUE"); | |
5126 seenModifyOtherKeys = TRUE; | 5160 seenModifyOtherKeys = TRUE; |
5127 | 5161 } |
5128 if (trail == 'u') | 5162 |
5129 key = arg[0]; | 5163 int key = trail == 'u' ? arg[0] : arg[2]; |
5130 else | 5164 int modifiers = decode_modifiers(arg[1]); |
5131 key = arg[2]; | 5165 return put_key_modifiers_in_typebuf(key, modifiers, |
5132 | 5166 csi_len, offset, buf, bufsize, buflen); |
5133 modifiers = decode_modifiers(arg[1]); | |
5134 | |
5135 // Some keys need adjustment when the Ctrl modifier is used. | |
5136 key = may_adjust_key_for_ctrl(modifiers, key); | |
5137 | |
5138 // May remove the shift modifier if it's already included in the key. | |
5139 modifiers = may_remove_shift_modifier(modifiers, key); | |
5140 | |
5141 // insert modifiers with KS_MODIFIER | |
5142 int new_slen = modifiers2keycode(modifiers, &key, string); | |
5143 | |
5144 // add the bytes for the key | |
5145 new_slen += add_key_to_buf(key, string + new_slen); | |
5146 | |
5147 if (put_string_in_typebuf(offset, csi_len, string, new_slen, | |
5148 buf, bufsize, buflen) == FAIL) | |
5149 return -1; | |
5150 return new_slen - csi_len + offset; | |
5151 } | 5167 } |
5152 | 5168 |
5153 /* | 5169 /* |
5154 * Handle a sequence with key without a modifier: | 5170 * Handle a sequence with key without a modifier: |
5155 * {lead}{key}u | 5171 * {lead}{key}u |
5181 | 5197 |
5182 if (put_string_in_typebuf(offset, csi_len, string, new_slen, | 5198 if (put_string_in_typebuf(offset, csi_len, string, new_slen, |
5183 buf, bufsize, buflen) == FAIL) | 5199 buf, bufsize, buflen) == FAIL) |
5184 return -1; | 5200 return -1; |
5185 return new_slen - csi_len + offset; | 5201 return new_slen - csi_len + offset; |
5202 } | |
5203 | |
5204 /* | |
5205 * CSI function key without or with modifiers: | |
5206 * {lead}[ABCDEFHPQRS] | |
5207 * {lead}1;{modifier}[ABCDEFHPQRS] | |
5208 * Returns zero when nog recognized, a positive number when recognized. | |
5209 */ | |
5210 static int | |
5211 handle_csi_function_key( | |
5212 int argc, | |
5213 int *arg, | |
5214 int trail, | |
5215 int csi_len, | |
5216 char_u *key_name, | |
5217 int offset, | |
5218 char_u *buf, | |
5219 int bufsize, | |
5220 int *buflen) | |
5221 { | |
5222 key_name[0] = 'k'; | |
5223 switch (trail) | |
5224 { | |
5225 case 'A': key_name[1] = 'u'; break; // K_UP | |
5226 case 'B': key_name[1] = 'd'; break; // K_DOWN | |
5227 case 'C': key_name[1] = 'r'; break; // K_RIGHT | |
5228 case 'D': key_name[1] = 'l'; break; // K_LEFT | |
5229 | |
5230 // case 'E': keypad BEGIN - not supported | |
5231 case 'F': key_name[0] = '@'; key_name[1] = '7'; break; // K_END | |
5232 case 'H': key_name[1] = 'h'; break; // K_HOME | |
5233 | |
5234 case 'P': key_name[1] = '1'; break; // K_F1 | |
5235 case 'Q': key_name[1] = '2'; break; // K_F2 | |
5236 case 'R': key_name[1] = '3'; break; // K_F3 | |
5237 case 'S': key_name[1] = '4'; break; // K_F4 | |
5238 | |
5239 default: return 0; // not recognized | |
5240 } | |
5241 | |
5242 int key = TERMCAP2KEY(key_name[0], key_name[1]); | |
5243 int modifiers = argc == 2 ? decode_modifiers(arg[1]) : 0; | |
5244 put_key_modifiers_in_typebuf(key, modifiers, | |
5245 csi_len, offset, buf, bufsize, buflen); | |
5246 return csi_len; | |
5186 } | 5247 } |
5187 | 5248 |
5188 /* | 5249 /* |
5189 * Handle a CSI escape sequence. | 5250 * Handle a CSI escape sequence. |
5190 * - Xterm version string. | 5251 * - Xterm version string. |
5195 * The final byte must be 'R'. It is used for checking the | 5256 * The final byte must be 'R'. It is used for checking the |
5196 * ambiguous-width character state. | 5257 * ambiguous-width character state. |
5197 * | 5258 * |
5198 * - window position reply: {lead}3;{x};{y}t | 5259 * - window position reply: {lead}3;{x};{y}t |
5199 * | 5260 * |
5200 * - key with modifiers when modifyOtherKeys is enabled: | 5261 * - key with modifiers when modifyOtherKeys is enabled or the Kitty keyboard |
5262 * protocol is used: | |
5201 * {lead}27;{modifier};{key}~ | 5263 * {lead}27;{modifier};{key}~ |
5202 * {lead}{key};{modifier}u | 5264 * {lead}{key};{modifier}u |
5265 * | |
5266 * - function key with or without modifiers: | |
5267 * {lead}[ABCDEFHPQRS] | |
5268 * {lead}1;{modifier}[ABCDEFHPQRS] | |
5203 * | 5269 * |
5204 * Return 0 for no match, -1 for partial match, > 0 for full match. | 5270 * Return 0 for no match, -1 for partial match, > 0 for full match. |
5205 */ | 5271 */ |
5206 static int | 5272 static int |
5207 handle_csi( | 5273 handle_csi( |
5216 int *slen) | 5282 int *slen) |
5217 { | 5283 { |
5218 int first = -1; // optional char right after {lead} | 5284 int first = -1; // optional char right after {lead} |
5219 int trail; // char that ends CSI sequence | 5285 int trail; // char that ends CSI sequence |
5220 int arg[3] = {-1, -1, -1}; // argument numbers | 5286 int arg[3] = {-1, -1, -1}; // argument numbers |
5221 int argc; // number of arguments | 5287 int argc = 0; // number of arguments |
5222 char_u *ap = argp; | 5288 char_u *ap = argp; |
5223 int csi_len; | 5289 int csi_len; |
5224 | 5290 |
5225 // Check for non-digit after CSI. | 5291 // Check for non-digit after CSI. |
5226 if (!VIM_ISDIGIT(*ap)) | 5292 if (!VIM_ISDIGIT(*ap)) |
5227 first = *ap++; | 5293 first = *ap++; |
5228 | 5294 |
5229 // Find up to three argument numbers. | 5295 if (ASCII_ISUPPER(first)) |
5230 for (argc = 0; argc < 3; ) | 5296 { |
5231 { | 5297 // If "first" is in [ABCDEFHPQRS] then it is actually the "trail" and |
5298 // no argument follows. | |
5299 trail = first; | |
5300 first = -1; | |
5301 --ap; | |
5302 } | |
5303 else | |
5304 { | |
5305 // Find up to three argument numbers. | |
5306 for (argc = 0; argc < 3; ) | |
5307 { | |
5308 if (ap >= tp + len) | |
5309 return -1; | |
5310 if (*ap == ';') | |
5311 arg[argc++] = -1; // omitted number | |
5312 else if (VIM_ISDIGIT(*ap)) | |
5313 { | |
5314 arg[argc] = 0; | |
5315 for (;;) | |
5316 { | |
5317 if (ap >= tp + len) | |
5318 return -1; | |
5319 if (!VIM_ISDIGIT(*ap)) | |
5320 break; | |
5321 arg[argc] = arg[argc] * 10 + (*ap - '0'); | |
5322 ++ap; | |
5323 } | |
5324 ++argc; | |
5325 } | |
5326 if (*ap == ';') | |
5327 ++ap; | |
5328 else | |
5329 break; | |
5330 } | |
5331 | |
5332 // mrxvt has been reported to have "+" in the version. Assume | |
5333 // the escape sequence ends with a letter or one of "{|}~". | |
5334 while (ap < tp + len | |
5335 && !(*ap >= '{' && *ap <= '~') | |
5336 && !ASCII_ISALPHA(*ap)) | |
5337 ++ap; | |
5232 if (ap >= tp + len) | 5338 if (ap >= tp + len) |
5233 return -1; | 5339 return -1; |
5234 if (*ap == ';') | 5340 trail = *ap; |
5235 arg[argc++] = -1; // omitted number | 5341 } |
5236 else if (VIM_ISDIGIT(*ap)) | 5342 |
5237 { | |
5238 arg[argc] = 0; | |
5239 for (;;) | |
5240 { | |
5241 if (ap >= tp + len) | |
5242 return -1; | |
5243 if (!VIM_ISDIGIT(*ap)) | |
5244 break; | |
5245 arg[argc] = arg[argc] * 10 + (*ap - '0'); | |
5246 ++ap; | |
5247 } | |
5248 ++argc; | |
5249 } | |
5250 if (*ap == ';') | |
5251 ++ap; | |
5252 else | |
5253 break; | |
5254 } | |
5255 | |
5256 // mrxvt has been reported to have "+" in the version. Assume | |
5257 // the escape sequence ends with a letter or one of "{|}~". | |
5258 while (ap < tp + len | |
5259 && !(*ap >= '{' && *ap <= '~') | |
5260 && !ASCII_ISALPHA(*ap)) | |
5261 ++ap; | |
5262 if (ap >= tp + len) | |
5263 return -1; | |
5264 trail = *ap; | |
5265 csi_len = (int)(ap - tp) + 1; | 5343 csi_len = (int)(ap - tp) + 1; |
5266 | 5344 |
5267 // Response to XTQMODKEYS: "CSI > 4 ; Pv m" where Pv indicates the | 5345 // Response to XTQMODKEYS: "CSI > 4 ; Pv m" where Pv indicates the |
5268 // modifyOtherKeys level. Drop similar responses. | 5346 // modifyOtherKeys level. Drop similar responses. |
5269 if (first == '>' && (argc == 1 || argc == 2) && trail == 'm') | 5347 if (first == '>' && (argc == 1 || argc == 2) && trail == 'm') |
5274 key_name[0] = (int)KS_EXTRA; | 5352 key_name[0] = (int)KS_EXTRA; |
5275 key_name[1] = (int)KE_IGNORE; | 5353 key_name[1] = (int)KE_IGNORE; |
5276 *slen = csi_len; | 5354 *slen = csi_len; |
5277 } | 5355 } |
5278 | 5356 |
5279 // Cursor position report: Eat it when there are 2 arguments | 5357 // Function key starting with CSI: |
5280 // and it ends in 'R'. Also when u7_status is not "sent", it | 5358 // {lead}[ABCDEFHPQRS] |
5281 // may be from a previous Vim that just exited. But not for | 5359 // {lead}1;{modifier}[ABCDEFHPQRS] |
5282 // <S-F3>, it sends something similar, check for row and column | 5360 else if (first == -1 && ASCII_ISUPPER(trail) |
5283 // to make sense. | 5361 && (argc == 0 || (argc == 2 && arg[0] == 1))) |
5362 { | |
5363 int res = handle_csi_function_key(argc, arg, trail, | |
5364 csi_len, key_name, offset, buf, bufsize, buflen); | |
5365 return res <= 0 ? res : len + res; | |
5366 } | |
5367 | |
5368 // Cursor position report: {lead}{row};{col}R | |
5369 // Eat it when there are 2 arguments and it ends in 'R'. | |
5370 // Also when u7_status is not "sent", it may be from a previous Vim that | |
5371 // just exited. But not for <S-F3>, it sends something similar, check for | |
5372 // row and column to make sense. | |
5284 else if (first == -1 && argc == 2 && trail == 'R') | 5373 else if (first == -1 && argc == 2 && trail == 'R') |
5285 { | 5374 { |
5286 handle_u7_response(arg, tp, csi_len); | 5375 handle_u7_response(arg, tp, csi_len); |
5287 | 5376 |
5288 key_name[0] = (int)KS_EXTRA; | 5377 key_name[0] = (int)KS_EXTRA; |
5344 { | 5433 { |
5345 kitty_protocol_state = KKPS_ENABLED; | 5434 kitty_protocol_state = KKPS_ENABLED; |
5346 | 5435 |
5347 // Reset seenModifyOtherKeys just in case some key combination has | 5436 // Reset seenModifyOtherKeys just in case some key combination has |
5348 // been seen that set it before we get the status response. | 5437 // been seen that set it before we get the status response. |
5438 ch_log(NULL, "setting seenModifyOtherKeys to FALSE"); | |
5349 seenModifyOtherKeys = FALSE; | 5439 seenModifyOtherKeys = FALSE; |
5350 } | 5440 } |
5351 | 5441 |
5352 key_name[0] = (int)KS_EXTRA; | 5442 key_name[0] = (int)KS_EXTRA; |
5353 key_name[1] = (int)KE_IGNORE; | 5443 key_name[1] = (int)KE_IGNORE; |
5914 { | 6004 { |
5915 char_u *argp = tp[0] == ESC ? tp + 2 : tp + 1; | 6005 char_u *argp = tp[0] == ESC ? tp + 2 : tp + 1; |
5916 | 6006 |
5917 /* | 6007 /* |
5918 * Check for responses from the terminal starting with {lead}: | 6008 * Check for responses from the terminal starting with {lead}: |
5919 * "<Esc>[" or CSI followed by [0-9>?] | 6009 * "<Esc>[" or CSI followed by [0-9>?]. |
6010 * Also for function keys without a modifier: | |
6011 * "<Esc>[" or CSI followed by [ABCDEFHPQRS]. | |
5920 * | 6012 * |
5921 * - Xterm version string: {lead}>{x};{vers};{y}c | 6013 * - Xterm version string: {lead}>{x};{vers};{y}c |
5922 * Also eat other possible responses to t_RV, rxvt returns | 6014 * Also eat other possible responses to t_RV, rxvt returns |
5923 * "{lead}?1;2c". | 6015 * "{lead}?1;2c". |
5924 * | 6016 * |
5933 * - key with modifiers when modifyOtherKeys is enabled: | 6025 * - key with modifiers when modifyOtherKeys is enabled: |
5934 * {lead}27;{modifier};{key}~ | 6026 * {lead}27;{modifier};{key}~ |
5935 * {lead}{key};{modifier}u | 6027 * {lead}{key};{modifier}u |
5936 */ | 6028 */ |
5937 if (((tp[0] == ESC && len >= 3 && tp[1] == '[') | 6029 if (((tp[0] == ESC && len >= 3 && tp[1] == '[') |
5938 || (tp[0] == CSI && len >= 2)) | 6030 || (tp[0] == CSI && len >= 2)) |
5939 && (VIM_ISDIGIT(*argp) || *argp == '>' || *argp == '?')) | 6031 && vim_strchr((char_u *)"0123456789>?ABCDEFHPQRS", |
6032 *argp) != NULL) | |
5940 { | 6033 { |
5941 int resp = handle_csi(tp, len, argp, offset, buf, | 6034 int resp = handle_csi(tp, len, argp, offset, buf, |
5942 bufsize, buflen, key_name, &slen); | 6035 bufsize, buflen, key_name, &slen); |
5943 if (resp != 0) | 6036 if (resp != 0) |
5944 { | 6037 { |
6422 } | 6515 } |
6423 #endif | 6516 #endif |
6424 slen = trans_special(&src, result + dlen, FSK_KEYCODE | 6517 slen = trans_special(&src, result + dlen, FSK_KEYCODE |
6425 | ((flags & REPTERM_NO_SIMPLIFY) ? 0 : FSK_SIMPLIFY), | 6518 | ((flags & REPTERM_NO_SIMPLIFY) ? 0 : FSK_SIMPLIFY), |
6426 TRUE, did_simplify); | 6519 TRUE, did_simplify); |
6427 if (slen) | 6520 if (slen > 0) |
6428 { | 6521 { |
6429 dlen += slen; | 6522 dlen += slen; |
6430 continue; | 6523 continue; |
6431 } | 6524 } |
6432 } | 6525 } |