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