xref: /haiku/src/apps/serialconnect/libvterm/src/input.c (revision d18836726c1cc8c2ebbf6991d9c4f2f917821357)
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