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