xref: /vim-8.2.3635/src/libvterm/src/keyboard.c (revision 591cec83)
1 #include "vterm_internal.h"
2 
3 #include <stdio.h>
4 
5 #include "utf8.h"
6 
vterm_is_modify_other_keys(VTerm * vt)7 int vterm_is_modify_other_keys(VTerm *vt)
8 {
9   return vt->state->mode.modify_other_keys;
10 }
11 
12 
vterm_keyboard_unichar(VTerm * vt,uint32_t c,VTermModifier mod)13 void vterm_keyboard_unichar(VTerm *vt, uint32_t c, VTermModifier mod)
14 {
15   int needs_CSIu;
16 
17   if (vt->state->mode.modify_other_keys && mod != 0) {
18     vterm_push_output_sprintf_ctrl(vt, C1_CSI, "27;%d;%d~", mod+1, c);
19     return;
20   }
21 
22   /* The shift modifier is never important for Unicode characters
23    * apart from Space
24    */
25   if(c != ' ')
26     mod &= ~VTERM_MOD_SHIFT;
27 
28   if(mod == 0) {
29     // Normal text - ignore just shift
30     char str[6];
31     int seqlen = fill_utf8(c, str);
32     vterm_push_output_bytes(vt, str, seqlen);
33     return;
34   }
35 
36   switch(c) {
37     /* Special Ctrl- letters that can't be represented elsewise */
38     case 'i': case 'j': case 'm': case '[':
39       needs_CSIu = 1;
40       break;
41     /* Ctrl-\ ] ^ _ don't need CSUu */
42     case '\\': case ']': case '^': case '_':
43       needs_CSIu = 0;
44       break;
45     /* Shift-space needs CSIu */
46     case ' ':
47       needs_CSIu = !!(mod & VTERM_MOD_SHIFT);
48       break;
49     /* All other characters needs CSIu except for letters a-z */
50     default:
51       needs_CSIu = (c < 'a' || c > 'z');
52   }
53 
54   /* ALT we can just prefix with ESC; anything else requires CSI u */
55   if(needs_CSIu && (mod & ~VTERM_MOD_ALT)) {
56     vterm_push_output_sprintf_ctrl(vt, C1_CSI, "%d;%du", c, mod+1);
57     return;
58   }
59 
60   if(mod & VTERM_MOD_CTRL)
61     c &= 0x1f;
62 
63   vterm_push_output_sprintf(vt, "%s%c", mod & VTERM_MOD_ALT ? ESC_S : "", c);
64 }
65 
66 typedef struct {
67   enum {
68     KEYCODE_NONE,
69     KEYCODE_LITERAL,
70     KEYCODE_TAB,
71     KEYCODE_ENTER,
72     KEYCODE_SS3,
73     KEYCODE_CSI,
74     KEYCODE_CSI_CURSOR,
75     KEYCODE_CSINUM,
76     KEYCODE_KEYPAD,
77   } type;
78   char literal;
79   int csinum;
80 } keycodes_s;
81 
82 // Order here must be exactly the same as VTermKey enum!
83 static keycodes_s keycodes[] = {
84   { KEYCODE_NONE,       0, 0 }, // NONE
85 
86   { KEYCODE_ENTER,      '\r', 0 }, // ENTER
87   { KEYCODE_TAB,        '\t',  0 }, // TAB
88   { KEYCODE_LITERAL,    '\x7f', 0 }, // BACKSPACE == ASCII DEL
89   { KEYCODE_LITERAL,    '\x1b', 0 }, // ESCAPE
90 
91   { KEYCODE_CSI_CURSOR, 'A', 0 }, // UP
92   { KEYCODE_CSI_CURSOR, 'B', 0 }, // DOWN
93   { KEYCODE_CSI_CURSOR, 'D', 0 }, // LEFT
94   { KEYCODE_CSI_CURSOR, 'C', 0 }, // RIGHT
95 
96   { KEYCODE_CSINUM,     '~', 2 }, // INS
97   { KEYCODE_CSINUM,     '~', 3 }, // DEL
98   { KEYCODE_CSI_CURSOR, 'H', 0 }, // HOME
99   { KEYCODE_CSI_CURSOR, 'F', 0 }, // END
100   { KEYCODE_CSINUM,     '~', 5 }, // PAGEUP
101   { KEYCODE_CSINUM,     '~', 6 }, // PAGEDOWN
102 };
103 
104 static keycodes_s keycodes_fn[] = {
105   { KEYCODE_NONE,       0, 0 },   // F0 - shouldn't happen
106   { KEYCODE_SS3,	'P', 0 }, // F1
107   { KEYCODE_SS3,	'Q', 0 }, // F2
108   { KEYCODE_SS3,	'R', 0 }, // F3
109   { KEYCODE_SS3,	'S', 0 }, // F4
110   { KEYCODE_CSINUM,     '~', 15 }, // F5
111   { KEYCODE_CSINUM,     '~', 17 }, // F6
112   { KEYCODE_CSINUM,     '~', 18 }, // F7
113   { KEYCODE_CSINUM,     '~', 19 }, // F8
114   { KEYCODE_CSINUM,     '~', 20 }, // F9
115   { KEYCODE_CSINUM,     '~', 21 }, // F10
116   { KEYCODE_CSINUM,     '~', 23 }, // F11
117   { KEYCODE_CSINUM,     '~', 24 }, // F12
118 };
119 
120 static keycodes_s keycodes_kp[] = {
121   { KEYCODE_KEYPAD, '0', 'p' }, // KP_0
122   { KEYCODE_KEYPAD, '1', 'q' }, // KP_1
123   { KEYCODE_KEYPAD, '2', 'r' }, // KP_2
124   { KEYCODE_KEYPAD, '3', 's' }, // KP_3
125   { KEYCODE_KEYPAD, '4', 't' }, // KP_4
126   { KEYCODE_KEYPAD, '5', 'u' }, // KP_5
127   { KEYCODE_KEYPAD, '6', 'v' }, // KP_6
128   { KEYCODE_KEYPAD, '7', 'w' }, // KP_7
129   { KEYCODE_KEYPAD, '8', 'x' }, // KP_8
130   { KEYCODE_KEYPAD, '9', 'y' }, // KP_9
131   { KEYCODE_KEYPAD, '*', 'j' }, // KP_MULT
132   { KEYCODE_KEYPAD, '+', 'k' }, // KP_PLUS
133   { KEYCODE_KEYPAD, ',', 'l' }, // KP_COMMA
134   { KEYCODE_KEYPAD, '-', 'm' }, // KP_MINUS
135   { KEYCODE_KEYPAD, '.', 'n' }, // KP_PERIOD
136   { KEYCODE_KEYPAD, '/', 'o' }, // KP_DIVIDE
137   { KEYCODE_KEYPAD, '\n', 'M' }, // KP_ENTER
138   { KEYCODE_KEYPAD, '=', 'X' }, // KP_EQUAL
139 };
140 
vterm_keyboard_key(VTerm * vt,VTermKey key,VTermModifier mod)141 void vterm_keyboard_key(VTerm *vt, VTermKey key, VTermModifier mod)
142 {
143   keycodes_s k;
144 
145   if(key == VTERM_KEY_NONE)
146     return;
147 
148   if(key < VTERM_KEY_FUNCTION_0) {
149     if(key >= sizeof(keycodes)/sizeof(keycodes[0]))
150       return;
151     k = keycodes[key];
152   }
153   else if(key >= VTERM_KEY_FUNCTION_0 && key <= VTERM_KEY_FUNCTION_MAX) {
154     if((key - VTERM_KEY_FUNCTION_0) >= sizeof(keycodes_fn)/sizeof(keycodes_fn[0]))
155       return;
156     k = keycodes_fn[key - VTERM_KEY_FUNCTION_0];
157   }
158   else if(key >= VTERM_KEY_KP_0) {
159     if((key - VTERM_KEY_KP_0) >= sizeof(keycodes_kp)/sizeof(keycodes_kp[0]))
160       return;
161     k = keycodes_kp[key - VTERM_KEY_KP_0];
162   }
163 
164   switch(k.type) {
165   case KEYCODE_NONE:
166     break;
167 
168   case KEYCODE_TAB:
169     /* Shift-Tab is CSI Z but plain Tab is 0x09 */
170     if(mod == VTERM_MOD_SHIFT)
171       vterm_push_output_sprintf_ctrl(vt, C1_CSI, "Z");
172     else if(mod & VTERM_MOD_SHIFT)
173       vterm_push_output_sprintf_ctrl(vt, C1_CSI, "1;%dZ", mod+1);
174     else
175       goto case_LITERAL;
176     break;
177 
178   case KEYCODE_ENTER:
179     /* Enter is CRLF in newline mode, but just LF in linefeed */
180     if(vt->state->mode.newline)
181       vterm_push_output_sprintf(vt, "\r\n");
182     else
183       goto case_LITERAL;
184     break;
185 
186   case KEYCODE_LITERAL: case_LITERAL:
187     if(mod & (VTERM_MOD_SHIFT|VTERM_MOD_CTRL))
188       vterm_push_output_sprintf_ctrl(vt, C1_CSI, "%d;%du", k.literal, mod+1);
189     else
190       vterm_push_output_sprintf(vt, mod & VTERM_MOD_ALT ? ESC_S "%c" : "%c", k.literal);
191     break;
192 
193   case KEYCODE_SS3: case_SS3:
194     if(mod == 0)
195       vterm_push_output_sprintf_ctrl(vt, C1_SS3, "%c", k.literal);
196     else
197       goto case_CSI;
198     break;
199 
200   case KEYCODE_CSI: case_CSI:
201     if(mod == 0)
202       vterm_push_output_sprintf_ctrl(vt, C1_CSI, "%c", k.literal);
203     else
204       vterm_push_output_sprintf_ctrl(vt, C1_CSI, "1;%d%c", mod + 1, k.literal);
205     break;
206 
207   case KEYCODE_CSINUM:
208     if(mod == 0)
209       vterm_push_output_sprintf_ctrl(vt, C1_CSI, "%d%c", k.csinum, k.literal);
210     else
211       vterm_push_output_sprintf_ctrl(vt, C1_CSI, "%d;%d%c", k.csinum, mod + 1, k.literal);
212     break;
213 
214   case KEYCODE_CSI_CURSOR:
215     if(vt->state->mode.cursor)
216       goto case_SS3;
217     else
218       goto case_CSI;
219 
220   case KEYCODE_KEYPAD:
221     if(vt->state->mode.keypad) {
222       k.literal = k.csinum;
223       goto case_SS3;
224     }
225     else
226       goto case_LITERAL;
227   }
228 }
229 
vterm_keyboard_start_paste(VTerm * vt)230 void vterm_keyboard_start_paste(VTerm *vt)
231 {
232   if(vt->state->mode.bracketpaste)
233     vterm_push_output_sprintf_ctrl(vt, C1_CSI, "200~");
234 }
235 
vterm_keyboard_end_paste(VTerm * vt)236 void vterm_keyboard_end_paste(VTerm *vt)
237 {
238   if(vt->state->mode.bracketpaste)
239     vterm_push_output_sprintf_ctrl(vt, C1_CSI, "201~");
240 }
241