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