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