1 // This is an open source non-commercial project. Dear PVS-Studio, please check
2 // it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
3 
4 #include <assert.h>
5 #include <inttypes.h>
6 #include <limits.h>
7 
8 #include "nvim/ascii.h"
9 #include "nvim/charset.h"
10 #include "nvim/edit.h"
11 #include "nvim/eval.h"
12 #include "nvim/keymap.h"
13 #include "nvim/memory.h"
14 #include "nvim/message.h"
15 #include "nvim/mouse.h"
16 #include "nvim/strings.h"
17 #include "nvim/vim.h"
18 
19 #ifdef INCLUDE_GENERATED_DECLARATIONS
20 # include "keymap.c.generated.h"
21 #endif
22 
23 /*
24  * Some useful tables.
25  */
26 
27 static const struct modmasktable {
28   uint16_t mod_mask;  ///< Bit-mask for particular key modifier.
29   uint16_t mod_flag;  ///< Bit(s) for particular key modifier.
30   char_u name;  ///< Single letter name of modifier.
31 } mod_mask_table[] = {
32   { MOD_MASK_ALT,              MOD_MASK_ALT,           (char_u)'M' },
33   { MOD_MASK_META,             MOD_MASK_META,          (char_u)'T' },
34   { MOD_MASK_CTRL,             MOD_MASK_CTRL,          (char_u)'C' },
35   { MOD_MASK_SHIFT,            MOD_MASK_SHIFT,         (char_u)'S' },
36   { MOD_MASK_MULTI_CLICK,      MOD_MASK_2CLICK,        (char_u)'2' },
37   { MOD_MASK_MULTI_CLICK,      MOD_MASK_3CLICK,        (char_u)'3' },
38   { MOD_MASK_MULTI_CLICK,      MOD_MASK_4CLICK,        (char_u)'4' },
39   { MOD_MASK_CMD,              MOD_MASK_CMD,           (char_u)'D' },
40   // 'A' must be the last one
41   { MOD_MASK_ALT,              MOD_MASK_ALT,           (char_u)'A' },
42   { 0, 0, NUL }
43   // NOTE: when adding an entry, update MAX_KEY_NAME_LEN!
44 };
45 
46 /*
47  * Shifted key terminal codes and their unshifted equivalent.
48  * Don't add mouse codes here, they are handled separately!
49  */
50 #define MOD_KEYS_ENTRY_SIZE 5
51 
52 static char_u modifier_keys_table[] =
53 {
54   //  mod mask      with modifier               without modifier
55   MOD_MASK_SHIFT, '&', '9',                   '@', '1',         // begin
56   MOD_MASK_SHIFT, '&', '0',                   '@', '2',         // cancel
57   MOD_MASK_SHIFT, '*', '1',                   '@', '4',         // command
58   MOD_MASK_SHIFT, '*', '2',                   '@', '5',         // copy
59   MOD_MASK_SHIFT, '*', '3',                   '@', '6',         // create
60   MOD_MASK_SHIFT, '*', '4',                   'k', 'D',         // delete char
61   MOD_MASK_SHIFT, '*', '5',                   'k', 'L',         // delete line
62   MOD_MASK_SHIFT, '*', '7',                   '@', '7',         // end
63   MOD_MASK_CTRL,  KS_EXTRA, (int)KE_C_END,    '@', '7',         // end
64   MOD_MASK_SHIFT, '*', '9',                   '@', '9',         // exit
65   MOD_MASK_SHIFT, '*', '0',                   '@', '0',         // find
66   MOD_MASK_SHIFT, '#', '1',                   '%', '1',         // help
67   MOD_MASK_SHIFT, '#', '2',                   'k', 'h',         // home
68   MOD_MASK_CTRL,  KS_EXTRA, (int)KE_C_HOME,   'k', 'h',         // home
69   MOD_MASK_SHIFT, '#', '3',                   'k', 'I',         // insert
70   MOD_MASK_SHIFT, '#', '4',                   'k', 'l',         // left arrow
71   MOD_MASK_CTRL,  KS_EXTRA, (int)KE_C_LEFT,   'k', 'l',         // left arrow
72   MOD_MASK_SHIFT, '%', 'a',                   '%', '3',         // message
73   MOD_MASK_SHIFT, '%', 'b',                   '%', '4',         // move
74   MOD_MASK_SHIFT, '%', 'c',                   '%', '5',         // next
75   MOD_MASK_SHIFT, '%', 'd',                   '%', '7',         // options
76   MOD_MASK_SHIFT, '%', 'e',                   '%', '8',         // previous
77   MOD_MASK_SHIFT, '%', 'f',                   '%', '9',         // print
78   MOD_MASK_SHIFT, '%', 'g',                   '%', '0',         // redo
79   MOD_MASK_SHIFT, '%', 'h',                   '&', '3',         // replace
80   MOD_MASK_SHIFT, '%', 'i',                   'k', 'r',         // right arr.
81   MOD_MASK_CTRL,  KS_EXTRA, (int)KE_C_RIGHT,  'k', 'r',         // right arr.
82   MOD_MASK_SHIFT, '%', 'j',                   '&', '5',         // resume
83   MOD_MASK_SHIFT, '!', '1',                   '&', '6',         // save
84   MOD_MASK_SHIFT, '!', '2',                   '&', '7',         // suspend
85   MOD_MASK_SHIFT, '!', '3',                   '&', '8',         // undo
86   MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_UP,     'k', 'u',         // up arrow
87   MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_DOWN,   'k', 'd',         // down arrow
88 
89   // vt100 F1
90   MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_XF1,    KS_EXTRA, (int)KE_XF1,
91   MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_XF2,    KS_EXTRA, (int)KE_XF2,
92   MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_XF3,    KS_EXTRA, (int)KE_XF3,
93   MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_XF4,    KS_EXTRA, (int)KE_XF4,
94 
95   MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F1,     'k', '1',         // F1
96   MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F2,     'k', '2',
97   MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F3,     'k', '3',
98   MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F4,     'k', '4',
99   MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F5,     'k', '5',
100   MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F6,     'k', '6',
101   MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F7,     'k', '7',
102   MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F8,     'k', '8',
103   MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F9,     'k', '9',
104   MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F10,    'k', ';',         // F10
105 
106   MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F11,    'F', '1',
107   MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F12,    'F', '2',
108   MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F13,    'F', '3',
109   MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F14,    'F', '4',
110   MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F15,    'F', '5',
111   MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F16,    'F', '6',
112   MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F17,    'F', '7',
113   MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F18,    'F', '8',
114   MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F19,    'F', '9',
115   MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F20,    'F', 'A',
116 
117   MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F21,    'F', 'B',
118   MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F22,    'F', 'C',
119   MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F23,    'F', 'D',
120   MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F24,    'F', 'E',
121   MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F25,    'F', 'F',
122   MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F26,    'F', 'G',
123   MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F27,    'F', 'H',
124   MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F28,    'F', 'I',
125   MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F29,    'F', 'J',
126   MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F30,    'F', 'K',
127 
128   MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F31,    'F', 'L',
129   MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F32,    'F', 'M',
130   MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F33,    'F', 'N',
131   MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F34,    'F', 'O',
132   MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F35,    'F', 'P',
133   MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F36,    'F', 'Q',
134   MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F37,    'F', 'R',
135 
136   // TAB pseudo code
137   MOD_MASK_SHIFT, 'k', 'B',                   KS_EXTRA, (int)KE_TAB,
138 
139   NUL
140 };
141 
142 static const struct key_name_entry {
143   int key;              // Special key code or ascii value
144   const char *name;           // Name of key
145 } key_names_table[] = {
146   { ' ',               "Space" },
147   { TAB,               "Tab" },
148   { K_TAB,             "Tab" },
149   { NL,                "NL" },
150   { NL,                "NewLine" },     // Alternative name
151   { NL,                "LineFeed" },    // Alternative name
152   { NL,                "LF" },          // Alternative name
153   { CAR,               "CR" },
154   { CAR,               "Return" },      // Alternative name
155   { CAR,               "Enter" },       // Alternative name
156   { K_BS,              "BS" },
157   { K_BS,              "BackSpace" },   // Alternative name
158   { ESC,               "Esc" },
159   { ESC,               "Escape" },      // Alternative name
160   { CSI,               "CSI" },
161   { K_CSI,             "xCSI" },
162   { '|',               "Bar" },
163   { '\\',              "Bslash" },
164   { K_DEL,             "Del" },
165   { K_DEL,             "Delete" },      // Alternative name
166   { K_KDEL,            "kDel" },
167   { K_KDEL,            "KPPeriod" },    // libtermkey name
168   { K_UP,              "Up" },
169   { K_DOWN,            "Down" },
170   { K_LEFT,            "Left" },
171   { K_RIGHT,           "Right" },
172   { K_XUP,             "xUp" },
173   { K_XDOWN,           "xDown" },
174   { K_XLEFT,           "xLeft" },
175   { K_XRIGHT,          "xRight" },
176   { K_KUP,             "kUp" },
177   { K_KUP,             "KP8" },
178   { K_KDOWN,           "kDown" },
179   { K_KDOWN,           "KP2" },
180   { K_KLEFT,           "kLeft" },
181   { K_KLEFT,           "KP4" },
182   { K_KRIGHT,          "kRight" },
183   { K_KRIGHT,          "KP6" },
184 
185   { K_F1,              "F1" },
186   { K_F2,              "F2" },
187   { K_F3,              "F3" },
188   { K_F4,              "F4" },
189   { K_F5,              "F5" },
190   { K_F6,              "F6" },
191   { K_F7,              "F7" },
192   { K_F8,              "F8" },
193   { K_F9,              "F9" },
194   { K_F10,             "F10" },
195 
196   { K_F11,             "F11" },
197   { K_F12,             "F12" },
198   { K_F13,             "F13" },
199   { K_F14,             "F14" },
200   { K_F15,             "F15" },
201   { K_F16,             "F16" },
202   { K_F17,             "F17" },
203   { K_F18,             "F18" },
204   { K_F19,             "F19" },
205   { K_F20,             "F20" },
206 
207   { K_F21,             "F21" },
208   { K_F22,             "F22" },
209   { K_F23,             "F23" },
210   { K_F24,             "F24" },
211   { K_F25,             "F25" },
212   { K_F26,             "F26" },
213   { K_F27,             "F27" },
214   { K_F28,             "F28" },
215   { K_F29,             "F29" },
216   { K_F30,             "F30" },
217 
218   { K_F31,             "F31" },
219   { K_F32,             "F32" },
220   { K_F33,             "F33" },
221   { K_F34,             "F34" },
222   { K_F35,             "F35" },
223   { K_F36,             "F36" },
224   { K_F37,             "F37" },
225 
226   { K_XF1,             "xF1" },
227   { K_XF2,             "xF2" },
228   { K_XF3,             "xF3" },
229   { K_XF4,             "xF4" },
230 
231   { K_HELP,            "Help" },
232   { K_UNDO,            "Undo" },
233   { K_INS,             "Insert" },
234   { K_INS,             "Ins" },         // Alternative name
235   { K_KINS,            "kInsert" },
236   { K_KINS,            "KP0" },
237   { K_HOME,            "Home" },
238   { K_KHOME,           "kHome" },
239   { K_KHOME,           "KP7" },
240   { K_XHOME,           "xHome" },
241   { K_ZHOME,           "zHome" },
242   { K_END,             "End" },
243   { K_KEND,            "kEnd" },
244   { K_KEND,            "KP1" },
245   { K_XEND,            "xEnd" },
246   { K_ZEND,            "zEnd" },
247   { K_PAGEUP,          "PageUp" },
248   { K_PAGEDOWN,        "PageDown" },
249   { K_KPAGEUP,         "kPageUp" },
250   { K_KPAGEUP,         "KP9" },
251   { K_KPAGEDOWN,       "kPageDown" },
252   { K_KPAGEDOWN,       "KP3" },
253   { K_KORIGIN,         "kOrigin" },
254   { K_KORIGIN,         "KP5" },
255 
256   { K_KPLUS,           "kPlus" },
257   { K_KPLUS,           "KPPlus" },
258   { K_KMINUS,          "kMinus" },
259   { K_KMINUS,          "KPMinus" },
260   { K_KDIVIDE,         "kDivide" },
261   { K_KDIVIDE,         "KPDiv" },
262   { K_KMULTIPLY,       "kMultiply" },
263   { K_KMULTIPLY,       "KPMult" },
264   { K_KENTER,          "kEnter" },
265   { K_KENTER,          "KPEnter" },
266   { K_KPOINT,          "kPoint" },
267   { K_KCOMMA,          "kComma" },
268   { K_KCOMMA,          "KPComma" },
269   { K_KEQUAL,          "kEqual" },
270   { K_KEQUAL,          "KPEquals" },
271 
272   { K_K0,              "k0" },
273   { K_K1,              "k1" },
274   { K_K2,              "k2" },
275   { K_K3,              "k3" },
276   { K_K4,              "k4" },
277   { K_K5,              "k5" },
278   { K_K6,              "k6" },
279   { K_K7,              "k7" },
280   { K_K8,              "k8" },
281   { K_K9,              "k9" },
282 
283   { '<',               "lt" },
284 
285   { K_MOUSE,           "Mouse" },
286   { K_LEFTMOUSE,       "LeftMouse" },
287   { K_LEFTMOUSE_NM,    "LeftMouseNM" },
288   { K_LEFTDRAG,        "LeftDrag" },
289   { K_LEFTRELEASE,     "LeftRelease" },
290   { K_LEFTRELEASE_NM,  "LeftReleaseNM" },
291   { K_MOUSEMOVE,       "MouseMove" },
292   { K_MIDDLEMOUSE,     "MiddleMouse" },
293   { K_MIDDLEDRAG,      "MiddleDrag" },
294   { K_MIDDLERELEASE,   "MiddleRelease" },
295   { K_RIGHTMOUSE,      "RightMouse" },
296   { K_RIGHTDRAG,       "RightDrag" },
297   { K_RIGHTRELEASE,    "RightRelease" },
298   { K_MOUSEDOWN,       "ScrollWheelUp" },
299   { K_MOUSEUP,         "ScrollWheelDown" },
300   { K_MOUSELEFT,       "ScrollWheelRight" },
301   { K_MOUSERIGHT,      "ScrollWheelLeft" },
302   { K_MOUSEDOWN,       "MouseDown" },   // OBSOLETE: Use
303   { K_MOUSEUP,         "MouseUp" },     // ScrollWheelXXX instead
304   { K_X1MOUSE,         "X1Mouse" },
305   { K_X1DRAG,          "X1Drag" },
306   { K_X1RELEASE,       "X1Release" },
307   { K_X2MOUSE,         "X2Mouse" },
308   { K_X2DRAG,          "X2Drag" },
309   { K_X2RELEASE,       "X2Release" },
310   { K_DROP,            "Drop" },
311   { K_ZERO,            "Nul" },
312   { K_SNR,             "SNR" },
313   { K_PLUG,            "Plug" },
314   { K_IGNORE,          "Ignore" },
315   { K_COMMAND,         "Cmd" },
316   { 0,                 NULL }
317   // NOTE: When adding a long name update MAX_KEY_NAME_LEN.
318 };
319 
320 static struct mousetable {
321   int pseudo_code;            // Code for pseudo mouse event
322   int button;                 // Which mouse button is it?
323   bool is_click;              // Is it a mouse button click event?
324   bool is_drag;               // Is it a mouse drag event?
325 } mouse_table[] =
326 {
327   { (int)KE_LEFTMOUSE,        MOUSE_LEFT,     true,   false },
328   { (int)KE_LEFTDRAG,         MOUSE_LEFT,     false,  true },
329   { (int)KE_LEFTRELEASE,      MOUSE_LEFT,     false,  false },
330   { (int)KE_MIDDLEMOUSE,      MOUSE_MIDDLE,   true,   false },
331   { (int)KE_MIDDLEDRAG,       MOUSE_MIDDLE,   false,  true },
332   { (int)KE_MIDDLERELEASE,    MOUSE_MIDDLE,   false,  false },
333   { (int)KE_RIGHTMOUSE,       MOUSE_RIGHT,    true,   false },
334   { (int)KE_RIGHTDRAG,        MOUSE_RIGHT,    false,  true },
335   { (int)KE_RIGHTRELEASE,     MOUSE_RIGHT,    false,  false },
336   { (int)KE_X1MOUSE,          MOUSE_X1,       true,   false },
337   { (int)KE_X1DRAG,           MOUSE_X1,       false,  true },
338   { (int)KE_X1RELEASE,        MOUSE_X1,       false,  false },
339   { (int)KE_X2MOUSE,          MOUSE_X2,       true,   false },
340   { (int)KE_X2DRAG,           MOUSE_X2,       false,  true },
341   { (int)KE_X2RELEASE,        MOUSE_X2,       false,  false },
342   // DRAG without CLICK
343   { (int)K_MOUSEMOVE,         MOUSE_RELEASE,  false,  true },
344   // RELEASE without CLICK
345   { (int)KE_IGNORE,           MOUSE_RELEASE,  false,  false },
346   { 0,                        0,              0,      0 },
347 };
348 
349 /// Return the modifier mask bit (#MOD_MASK_*) corresponding to mod name
350 ///
351 /// E.g. 'S' for shift, 'C' for ctrl.
name_to_mod_mask(int c)352 int name_to_mod_mask(int c)
353   FUNC_ATTR_CONST FUNC_ATTR_WARN_UNUSED_RESULT
354 {
355   c = TOUPPER_ASC(c);
356   for (size_t i = 0; mod_mask_table[i].mod_mask != 0; i++) {
357     if (c == mod_mask_table[i].name) {
358       return mod_mask_table[i].mod_flag;
359     }
360   }
361   return 0;
362 }
363 
364 /// Check if there is a special key code for "key" with specified modifiers
365 ///
366 /// @param[in]  key  Initial key code.
367 /// @param[in,out]  modifiers  Initial modifiers, is adjusted to have simplified
368 ///                            modifiers.
369 ///
370 /// @return Simplified key code.
simplify_key(const int key,int * modifiers)371 int simplify_key(const int key, int *modifiers)
372   FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL
373 {
374   if (*modifiers & (MOD_MASK_SHIFT | MOD_MASK_CTRL | MOD_MASK_ALT)) {
375     // TAB is a special case.
376     if (key == TAB && (*modifiers & MOD_MASK_SHIFT)) {
377       *modifiers &= ~MOD_MASK_SHIFT;
378       return K_S_TAB;
379     }
380     const int key0 = KEY2TERMCAP0(key);
381     const int key1 = KEY2TERMCAP1(key);
382     for (int i = 0; modifier_keys_table[i] != NUL; i += MOD_KEYS_ENTRY_SIZE) {
383       if (key0 == modifier_keys_table[i + 3]
384           && key1 == modifier_keys_table[i + 4]
385           && (*modifiers & modifier_keys_table[i])) {
386         *modifiers &= ~modifier_keys_table[i];
387         return TERMCAP2KEY(modifier_keys_table[i + 1],
388                            modifier_keys_table[i + 2]);
389       }
390     }
391   }
392   return key;
393 }
394 
395 /// Change <xKey> to <Key>
handle_x_keys(const int key)396 int handle_x_keys(const int key)
397   FUNC_ATTR_CONST FUNC_ATTR_WARN_UNUSED_RESULT
398 {
399   switch (key) {
400   case K_XUP:
401     return K_UP;
402   case K_XDOWN:
403     return K_DOWN;
404   case K_XLEFT:
405     return K_LEFT;
406   case K_XRIGHT:
407     return K_RIGHT;
408   case K_XHOME:
409     return K_HOME;
410   case K_ZHOME:
411     return K_HOME;
412   case K_XEND:
413     return K_END;
414   case K_ZEND:
415     return K_END;
416   case K_XF1:
417     return K_F1;
418   case K_XF2:
419     return K_F2;
420   case K_XF3:
421     return K_F3;
422   case K_XF4:
423     return K_F4;
424   case K_S_XF1:
425     return K_S_F1;
426   case K_S_XF2:
427     return K_S_F2;
428   case K_S_XF3:
429     return K_S_F3;
430   case K_S_XF4:
431     return K_S_F4;
432   }
433   return key;
434 }
435 
436 /*
437  * Return a string which contains the name of the given key when the given
438  * modifiers are down.
439  */
get_special_key_name(int c,int modifiers)440 char_u *get_special_key_name(int c, int modifiers)
441 {
442   static char_u string[MAX_KEY_NAME_LEN + 1];
443 
444   int i, idx;
445   int table_idx;
446   char_u *s;
447 
448   string[0] = '<';
449   idx = 1;
450 
451   // Key that stands for a normal character.
452   if (IS_SPECIAL(c) && KEY2TERMCAP0(c) == KS_KEY) {
453     c = KEY2TERMCAP1(c);
454   }
455 
456   /*
457    * Translate shifted special keys into unshifted keys and set modifier.
458    * Same for CTRL and ALT modifiers.
459    */
460   if (IS_SPECIAL(c)) {
461     for (i = 0; modifier_keys_table[i] != 0; i += MOD_KEYS_ENTRY_SIZE) {
462       if (KEY2TERMCAP0(c) == (int)modifier_keys_table[i + 1]
463           && (int)KEY2TERMCAP1(c) == (int)modifier_keys_table[i + 2]) {
464         modifiers |= modifier_keys_table[i];
465         c = TERMCAP2KEY(modifier_keys_table[i + 3],
466                         modifier_keys_table[i + 4]);
467         break;
468       }
469     }
470   }
471 
472   // try to find the key in the special key table
473   table_idx = find_special_key_in_table(c);
474 
475   /*
476    * When not a known special key, and not a printable character, try to
477    * extract modifiers.
478    */
479   if (c > 0
480       && utf_char2len(c) == 1) {
481     if (table_idx < 0
482         && (!vim_isprintc(c) || (c & 0x7f) == ' ')
483         && (c & 0x80)) {
484       c &= 0x7f;
485       modifiers |= MOD_MASK_ALT;
486       // try again, to find the un-alted key in the special key table
487       table_idx = find_special_key_in_table(c);
488     }
489     if (table_idx < 0 && !vim_isprintc(c) && c < ' ') {
490       c += '@';
491       modifiers |= MOD_MASK_CTRL;
492     }
493   }
494 
495   // translate the modifier into a string
496   for (i = 0; mod_mask_table[i].name != 'A'; i++) {
497     if ((modifiers & mod_mask_table[i].mod_mask)
498         == mod_mask_table[i].mod_flag) {
499       string[idx++] = mod_mask_table[i].name;
500       string[idx++] = (char_u)'-';
501     }
502   }
503 
504   if (table_idx < 0) {          // unknown special key, may output t_xx
505     if (IS_SPECIAL(c)) {
506       string[idx++] = 't';
507       string[idx++] = '_';
508       string[idx++] = (char_u)KEY2TERMCAP0(c);
509       string[idx++] = KEY2TERMCAP1(c);
510     } else {
511       // Not a special key, only modifiers, output directly.
512       if (utf_char2len(c) > 1) {
513         idx += utf_char2bytes(c, string + idx);
514       } else if (vim_isprintc(c)) {
515         string[idx++] = (char_u)c;
516       } else {
517         s = transchar(c);
518         while (*s) {
519           string[idx++] = *s++;
520         }
521       }
522     }
523   } else {            // use name of special key
524     size_t len = STRLEN(key_names_table[table_idx].name);
525 
526     if ((int)len + idx + 2 <= MAX_KEY_NAME_LEN) {
527       STRCPY(string + idx, key_names_table[table_idx].name);
528       idx += (int)len;
529     }
530   }
531   string[idx++] = '>';
532   string[idx] = NUL;
533   return string;
534 }
535 
536 /// Try translating a <> name ("keycode").
537 ///
538 /// @param[in,out]  srcp  Source from which <> are translated. Is advanced to
539 ///                       after the <> name if there is a match.
540 /// @param[in]  src_len  Length of the srcp.
541 /// @param[out]  dst  Location where translation result will be kept. It must
542 //                    be at least 19 bytes per "<x>" form.
543 /// @param[in]  keycode  Prefer key code, e.g. K_DEL in place of DEL.
544 /// @param[in]  in_string  Inside a double quoted string
545 ///
546 /// @return Number of characters added to dst, zero for no match.
trans_special(const char_u ** srcp,const size_t src_len,char_u * const dst,const bool keycode,const bool in_string)547 unsigned int trans_special(const char_u **srcp, const size_t src_len, char_u *const dst,
548                            const bool keycode, const bool in_string)
549   FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
550 {
551   int modifiers = 0;
552   int key;
553 
554   key = find_special_key(srcp, src_len, &modifiers, keycode, false, in_string);
555   if (key == 0) {
556     return 0;
557   }
558 
559   return special_to_buf(key, modifiers, keycode, dst);
560 }
561 
562 /// Put the character sequence for "key" with "modifiers" into "dst" and return
563 /// the resulting length.
564 /// When "keycode" is true prefer key code, e.g. K_DEL instead of DEL.
565 /// The sequence is not NUL terminated.
566 /// This is how characters in a string are encoded.
special_to_buf(int key,int modifiers,bool keycode,char_u * dst)567 unsigned int special_to_buf(int key, int modifiers, bool keycode, char_u *dst)
568 {
569   unsigned int dlen = 0;
570 
571   // Put the appropriate modifier in a string.
572   if (modifiers != 0) {
573     dst[dlen++] = K_SPECIAL;
574     dst[dlen++] = KS_MODIFIER;
575     dst[dlen++] = (char_u)modifiers;
576   }
577 
578   if (IS_SPECIAL(key)) {
579     dst[dlen++] = K_SPECIAL;
580     dst[dlen++] = (char_u)KEY2TERMCAP0(key);
581     dst[dlen++] = KEY2TERMCAP1(key);
582   } else if (!keycode) {
583     dlen += (unsigned int)utf_char2bytes(key, dst + dlen);
584   } else {
585     char_u *after = add_char2buf(key, dst + dlen);
586     assert(after >= dst && (uintmax_t)(after - dst) <= UINT_MAX);
587     dlen = (unsigned int)(after - dst);
588   }
589 
590   return dlen;
591 }
592 
593 /// Try translating a <> name
594 ///
595 /// @param[in,out]  srcp  Translated <> name. Is advanced to after the <> name.
596 /// @param[in]  src_len  srcp length.
597 /// @param[out]  modp  Location where information about modifiers is saved.
598 /// @param[in]  keycode  Prefer key code, e.g. K_DEL in place of DEL.
599 /// @param[in]  keep_x_key  Don’t translate xHome to Home key.
600 /// @param[in]  in_string  In string, double quote is escaped
601 ///
602 /// @return Key and modifiers or 0 if there is no match.
find_special_key(const char_u ** srcp,const size_t src_len,int * const modp,const bool keycode,const bool keep_x_key,const bool in_string)603 int find_special_key(const char_u **srcp, const size_t src_len, int *const modp, const bool keycode,
604                      const bool keep_x_key, const bool in_string)
605   FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL
606 {
607   const char_u *last_dash;
608   const char_u *end_of_name;
609   const char_u *src;
610   const char_u *bp;
611   const char_u *const end = *srcp + src_len - 1;
612   int modifiers;
613   int bit;
614   int key;
615   uvarnumber_T n;
616   int l;
617 
618   if (src_len == 0) {
619     return 0;
620   }
621 
622   src = *srcp;
623   if (src[0] != '<') {
624     return 0;
625   }
626 
627   // Find end of modifier list
628   last_dash = src;
629   for (bp = src + 1; bp <= end && (*bp == '-' || ascii_isident(*bp)); bp++) {
630     if (*bp == '-') {
631       last_dash = bp;
632       if (bp + 1 <= end) {
633         l = utfc_ptr2len_len(bp + 1, (int)(end - bp) + 1);
634         // Anything accepted, like <C-?>.
635         // <C-"> or <M-"> are not special in strings as " is
636         // the string delimiter. With a backslash it works: <M-\">
637         if (end - bp > l && !(in_string && bp[1] == '"') && bp[l+1] == '>') {
638           bp += l;
639         } else if (end - bp > 2 && in_string && bp[1] == '\\'
640                    && bp[2] == '"' && bp[3] == '>') {
641           bp += 2;
642         }
643       }
644     }
645     if (end - bp > 3 && bp[0] == 't' && bp[1] == '_') {
646       bp += 3;  // skip t_xx, xx may be '-' or '>'
647     } else if (end - bp > 4 && STRNICMP(bp, "char-", 5) == 0) {
648       vim_str2nr(bp + 5, NULL, &l, STR2NR_ALL, NULL, NULL, 0, true);
649       if (l == 0) {
650         emsg(_(e_invarg));
651         return 0;
652       }
653       bp += l + 5;
654       break;
655     }
656   }
657 
658   if (bp <= end && *bp == '>') {  // found matching '>'
659     end_of_name = bp + 1;
660 
661     // Which modifiers are given?
662     modifiers = 0x0;
663     for (bp = src + 1; bp < last_dash; bp++) {
664       if (*bp != '-') {
665         bit = name_to_mod_mask(*bp);
666         if (bit == 0x0) {
667           break;                // Illegal modifier name
668         }
669         modifiers |= bit;
670       }
671     }
672 
673     // Legal modifier name.
674     if (bp >= last_dash) {
675       if (STRNICMP(last_dash + 1, "char-", 5) == 0
676           && ascii_isdigit(last_dash[6])) {
677         // <Char-123> or <Char-033> or <Char-0x33>
678         vim_str2nr(last_dash + 6, NULL, &l, STR2NR_ALL, NULL, &n, 0, true);
679         if (l == 0) {
680           emsg(_(e_invarg));
681           return 0;
682         }
683         key = (int)n;
684       } else {
685         int off = 1;
686 
687         // Modifier with single letter, or special key name.
688         if (in_string && last_dash[1] == '\\' && last_dash[2] == '"') {
689           // Special case for a double-quoted string
690           off = l = 2;
691         } else {
692           l = utfc_ptr2len(last_dash + 1);
693         }
694         if (modifiers != 0 && last_dash[l + 1] == '>') {
695           key = utf_ptr2char(last_dash + off);
696         } else {
697           key = get_special_key_code(last_dash + off);
698           if (!keep_x_key) {
699             key = handle_x_keys(key);
700           }
701         }
702       }
703 
704       // get_special_key_code() may return NUL for invalid
705       // special key name.
706       if (key != NUL) {
707         // Only use a modifier when there is no special key code that
708         // includes the modifier.
709         key = simplify_key(key, &modifiers);
710 
711         if (!keycode) {
712           // don't want keycode, use single byte code
713           if (key == K_BS) {
714             key = BS;
715           } else if (key == K_DEL || key == K_KDEL) {
716             key = DEL;
717           }
718         }
719 
720         // Normal Key with modifier:
721         // Try to make a single byte code (except for Alt/Meta modifiers).
722         if (!IS_SPECIAL(key)) {
723           key = extract_modifiers(key, &modifiers);
724         }
725 
726         *modp = modifiers;
727         *srcp = end_of_name;
728         return key;
729       }  // else { ELOG("unknown key: '%s'", src); }
730     }
731   }
732   return 0;
733 }
734 
735 /// Try to include modifiers (except alt/meta) in the key.
736 /// Changes "Shift-a" to 'A', "Ctrl-@" to <Nul>, etc.
extract_modifiers(int key,int * modp)737 static int extract_modifiers(int key, int *modp)
738 {
739   int modifiers = *modp;
740 
741   // Command-key and ctrl are special
742   if (!(modifiers & MOD_MASK_CMD) && !(modifiers & MOD_MASK_CTRL)) {
743     if ((modifiers & MOD_MASK_SHIFT) && ASCII_ISALPHA(key)) {
744       key = TOUPPER_ASC(key);
745       modifiers &= ~MOD_MASK_SHIFT;
746     }
747   }
748   if ((modifiers & MOD_MASK_CTRL)
749       && ((key >= '?' && key <= '_') || ASCII_ISALPHA(key))) {
750     key = Ctrl_chr(key);
751     modifiers &= ~MOD_MASK_CTRL;
752     if (key == 0) {  // <C-@> is <Nul>
753       key = K_ZERO;
754     }
755   }
756 
757   *modp = modifiers;
758   return key;
759 }
760 
761 /*
762  * Try to find key "c" in the special key table.
763  * Return the index when found, -1 when not found.
764  */
find_special_key_in_table(int c)765 int find_special_key_in_table(int c)
766 {
767   int i;
768 
769   for (i = 0; key_names_table[i].name != NULL; i++) {
770     if (c == key_names_table[i].key) {
771       break;
772     }
773   }
774   if (key_names_table[i].name == NULL) {
775     i = -1;
776   }
777   return i;
778 }
779 
780 /// Find the special key with the given name
781 ///
782 /// @param[in]  name  Name of the special. Does not have to end with NUL, it is
783 ///                   assumed to end before the first non-idchar. If name starts
784 ///                   with "t_" the next two characters are interpreted as
785 ///                   a termcap name.
786 ///
787 /// @return Key code or 0 if not found.
get_special_key_code(const char_u * name)788 int get_special_key_code(const char_u *name)
789   FUNC_ATTR_NONNULL_ALL FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT
790 {
791   for (int i = 0; key_names_table[i].name != NULL; i++) {
792     const char *const table_name = key_names_table[i].name;
793     int j;
794     for (j = 0; ascii_isident(name[j]) && table_name[j] != NUL; j++) {
795       if (TOLOWER_ASC(table_name[j]) != TOLOWER_ASC(name[j])) {
796         break;
797       }
798     }
799     if (!ascii_isident(name[j]) && table_name[j] == NUL) {
800       return key_names_table[i].key;
801     }
802   }
803 
804   return 0;
805 }
806 
807 /*
808  * Look up the given mouse code to return the relevant information in the other
809  * arguments.  Return which button is down or was released.
810  */
get_mouse_button(int code,bool * is_click,bool * is_drag)811 int get_mouse_button(int code, bool *is_click, bool *is_drag)
812 {
813   int i;
814 
815   for (i = 0; mouse_table[i].pseudo_code; i++) {
816     if (code == mouse_table[i].pseudo_code) {
817       *is_click = mouse_table[i].is_click;
818       *is_drag = mouse_table[i].is_drag;
819       return mouse_table[i].button;
820     }
821   }
822   return 0;         // Shouldn't get here
823 }
824 
825 /// Replace any terminal code strings with the equivalent internal
826 /// representation
827 ///
828 /// Used for the "from" and "to" part of a mapping, and the "to" part of
829 /// a menu command. Any strings like "<C-UP>" are also replaced, unless
830 /// `special` is false. K_SPECIAL by itself is replaced by K_SPECIAL
831 /// KS_SPECIAL KE_FILLER.
832 ///
833 /// @param[in]  from  What characters to replace.
834 /// @param[in]  from_len  Length of the "from" argument.
835 /// @param[out]  bufp  Location where results were saved in case of success
836 ///                    (allocated). Will be set to NULL in case of failure.
837 /// @param[in]  do_lt  If true, also translate <lt>.
838 /// @param[in]  from_part  If true, trailing <C-v> is included, otherwise it is
839 ///                        removed (to make ":map xx ^V" map xx to nothing).
840 ///                        When cpo_flags contains #FLAG_CPO_BSLASH, a backslash
841 ///                        can be used in place of <C-v>. All other <C-v>
842 ///                        characters are removed.
843 /// @param[in]  special    Replace keycodes, e.g. <CR> becomes a "\n" char.
844 /// @param[in]  cpo_flags  Relevant flags derived from p_cpo, see
845 ///                        #CPO_TO_CPO_FLAGS.
846 ///
847 /// @return Pointer to an allocated memory in case of success, "from" in case of
848 ///         failure. In case of success returned pointer is also saved to
849 ///         "bufp".
replace_termcodes(const char_u * from,const size_t from_len,char_u ** bufp,const bool from_part,const bool do_lt,const bool special,int cpo_flags)850 char_u *replace_termcodes(const char_u *from, const size_t from_len, char_u **bufp,
851                           const bool from_part, const bool do_lt, const bool special, int cpo_flags)
852   FUNC_ATTR_NONNULL_ALL
853 {
854   ssize_t i;
855   size_t slen;
856   char_u key;
857   size_t dlen = 0;
858   const char_u *src;
859   const char_u *const end = from + from_len - 1;
860   int do_backslash;             // backslash is a special character
861   char_u *result;          // buffer for resulting string
862 
863   do_backslash = !(cpo_flags&FLAG_CPO_BSLASH);
864 
865   // Allocate space for the translation.  Worst case a single character is
866   // replaced by 6 bytes (shifted special key), plus a NUL at the end.
867   const size_t buf_len = from_len * 6 + 1;
868   result = xmalloc(buf_len);
869 
870   src = from;
871 
872   // Check for #n at start only: function key n
873   if (from_part && from_len > 1 && src[0] == '#'
874       && ascii_isdigit(src[1])) {  // function key
875     result[dlen++] = K_SPECIAL;
876     result[dlen++] = 'k';
877     if (src[1] == '0') {
878       result[dlen++] = ';';     // #0 is F10 is "k;"
879     } else {
880       result[dlen++] = src[1];  // #3 is F3 is "k3"
881     }
882     src += 2;
883   }
884 
885   // Copy each byte from *from to result[dlen]
886   while (src <= end) {
887     // Check for special <> keycodes, like "<C-S-LeftMouse>"
888     if (special && (do_lt || ((end - src) >= 3
889                               && STRNCMP(src, "<lt>", 4) != 0))) {
890       // Replace <SID> by K_SNR <script-nr> _.
891       // (room: 5 * 6 = 30 bytes; needed: 3 + <nr> + 1 <= 14)
892       if (end - src >= 4 && STRNICMP(src, "<SID>", 5) == 0) {
893         if (current_sctx.sc_sid <= 0) {
894           emsg(_(e_usingsid));
895         } else {
896           src += 5;
897           result[dlen++] = K_SPECIAL;
898           result[dlen++] = (int)KS_EXTRA;
899           result[dlen++] = (int)KE_SNR;
900           snprintf((char *)result + dlen, buf_len - dlen, "%" PRId64,
901                    (int64_t)current_sctx.sc_sid);
902           dlen += STRLEN(result + dlen);
903           result[dlen++] = '_';
904           continue;
905         }
906       }
907 
908       slen = trans_special(&src, (size_t)(end - src) + 1, result + dlen, true,
909                            false);
910       if (slen) {
911         dlen += slen;
912         continue;
913       }
914     }
915 
916     if (special) {
917       char_u *p, *s, len;
918 
919       // Replace <Leader> by the value of "mapleader".
920       // Replace <LocalLeader> by the value of "maplocalleader".
921       // If "mapleader" or "maplocalleader" isn't set use a backslash.
922       if (end - src >= 7 && STRNICMP(src, "<Leader>", 8) == 0) {
923         len = 8;
924         p = get_var_value("g:mapleader");
925       } else if (end - src >= 12 && STRNICMP(src, "<LocalLeader>", 13) == 0) {
926         len = 13;
927         p = get_var_value("g:maplocalleader");
928       } else {
929         len = 0;
930         p = NULL;
931       }
932 
933       if (len != 0) {
934         // Allow up to 8 * 6 characters for "mapleader".
935         if (p == NULL || *p == NUL || STRLEN(p) > 8 * 6) {
936           s = (char_u *)"\\";
937         } else {
938           s = p;
939         }
940         while (*s != NUL) {
941           result[dlen++] = *s++;
942         }
943         src += len;
944         continue;
945       }
946     }
947 
948     // Remove CTRL-V and ignore the next character.
949     // For "from" side the CTRL-V at the end is included, for the "to"
950     // part it is removed.
951     // If 'cpoptions' does not contain 'B', also accept a backslash.
952     key = *src;
953     if (key == Ctrl_V || (do_backslash && key == '\\')) {
954       src++;  // skip CTRL-V or backslash
955       if (src > end) {
956         if (from_part) {
957           result[dlen++] = key;
958         }
959         break;
960       }
961     }
962 
963     // skip multibyte char correctly
964     for (i = utfc_ptr2len_len(src, (int)(end - src) + 1); i > 0; i--) {
965       // If the character is K_SPECIAL, replace it with K_SPECIAL
966       // KS_SPECIAL KE_FILLER.
967       // If compiled with the GUI replace CSI with K_CSI.
968       if (*src == K_SPECIAL) {
969         result[dlen++] = K_SPECIAL;
970         result[dlen++] = KS_SPECIAL;
971         result[dlen++] = KE_FILLER;
972       } else {
973         result[dlen++] = *src;
974       }
975       ++src;
976     }
977   }
978   result[dlen] = NUL;
979 
980   *bufp = xrealloc(result, dlen + 1);
981 
982   return *bufp;
983 }
984 
985 /// Logs a single key as a human-readable keycode.
log_key(int log_level,int key)986 void log_key(int log_level, int key)
987 {
988   if (log_level < MIN_LOG_LEVEL) {
989     return;
990   }
991   char *keyname = key == K_EVENT
992     ? "K_EVENT"
993     : (char *)get_special_key_name(key, mod_mask);
994   LOG(log_level, "input: %s", keyname);
995 }
996