1#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  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
51typedef 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
67static 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
88static 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
104static 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
125void 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