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