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