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 }