1 #include "termkey.h"
2 #include "termkey-internal.h"
3
4 #include <stdio.h>
5 #include <string.h>
6
7 // There are 64 codes 0x40 - 0x7F
8 static int keyinfo_initialised = 0;
9 static struct keyinfo ss3s[64];
10 static char ss3_kpalts[64];
11
12 typedef struct {
13 TermKey *tk;
14 int saved_string_id;
15 char *saved_string;
16 } TermKeyCsi;
17
18 typedef TermKeyResult CsiHandler(TermKey *tk, TermKeyKey *key, int cmd, long *arg, int args);
19 static CsiHandler *csi_handlers[64];
20
21 /*
22 * Handler for CSI/SS3 cmd keys
23 */
24
25 static struct keyinfo csi_ss3s[64];
26
handle_csi_ss3_full(TermKey * tk,TermKeyKey * key,int cmd,long * arg,int args)27 static TermKeyResult handle_csi_ss3_full(TermKey *tk, TermKeyKey *key, int cmd, long *arg, int args)
28 {
29 if(args > 1 && arg[1] != -1)
30 key->modifiers = arg[1] - 1;
31 else
32 key->modifiers = 0;
33
34 key->type = csi_ss3s[cmd - 0x40].type;
35 key->code.sym = csi_ss3s[cmd - 0x40].sym;
36 key->modifiers &= ~(csi_ss3s[cmd - 0x40].modifier_mask);
37 key->modifiers |= csi_ss3s[cmd - 0x40].modifier_set;
38
39 if(key->code.sym == TERMKEY_SYM_UNKNOWN)
40 return TERMKEY_RES_NONE;
41
42 return TERMKEY_RES_KEY;
43 }
44
register_csi_ss3_full(TermKeyType type,TermKeySym sym,int modifier_set,int modifier_mask,unsigned char cmd)45 static void register_csi_ss3_full(TermKeyType type, TermKeySym sym, int modifier_set, int modifier_mask, unsigned char cmd)
46 {
47 if(cmd < 0x40 || cmd >= 0x80) {
48 return;
49 }
50
51 csi_ss3s[cmd - 0x40].type = type;
52 csi_ss3s[cmd - 0x40].sym = sym;
53 csi_ss3s[cmd - 0x40].modifier_set = modifier_set;
54 csi_ss3s[cmd - 0x40].modifier_mask = modifier_mask;
55
56 csi_handlers[cmd - 0x40] = &handle_csi_ss3_full;
57 }
58
register_csi_ss3(TermKeyType type,TermKeySym sym,unsigned char cmd)59 static void register_csi_ss3(TermKeyType type, TermKeySym sym, unsigned char cmd)
60 {
61 register_csi_ss3_full(type, sym, 0, 0, cmd);
62 }
63
64 /*
65 * Handler for SS3 keys with kpad alternate representations
66 */
67
register_ss3kpalt(TermKeyType type,TermKeySym sym,unsigned char cmd,char kpalt)68 static void register_ss3kpalt(TermKeyType type, TermKeySym sym, unsigned char cmd, char kpalt)
69 {
70 if(cmd < 0x40 || cmd >= 0x80) {
71 return;
72 }
73
74 ss3s[cmd - 0x40].type = type;
75 ss3s[cmd - 0x40].sym = sym;
76 ss3s[cmd - 0x40].modifier_set = 0;
77 ss3s[cmd - 0x40].modifier_mask = 0;
78 ss3_kpalts[cmd - 0x40] = kpalt;
79 }
80
81 /*
82 * Handler for CSI number ~ function keys
83 */
84
85 static struct keyinfo csifuncs[35]; /* This value must be increased if more CSI function keys are added */
86 #define NCSIFUNCS (sizeof(csifuncs)/sizeof(csifuncs[0]))
87
handle_csifunc(TermKey * tk,TermKeyKey * key,int cmd,long * arg,int args)88 static TermKeyResult handle_csifunc(TermKey *tk, TermKeyKey *key, int cmd, long *arg, int args)
89 {
90 if(args > 1 && arg[1] != -1)
91 key->modifiers = arg[1] - 1;
92 else
93 key->modifiers = 0;
94
95 key->type = TERMKEY_TYPE_KEYSYM;
96
97 if(arg[0] == 27) {
98 int mod = key->modifiers;
99 (*tk->method.emit_codepoint)(tk, arg[2], key);
100 key->modifiers |= mod;
101 }
102 else if(arg[0] >= 0 && arg[0] < NCSIFUNCS) {
103 key->type = csifuncs[arg[0]].type;
104 key->code.sym = csifuncs[arg[0]].sym;
105 key->modifiers &= ~(csifuncs[arg[0]].modifier_mask);
106 key->modifiers |= csifuncs[arg[0]].modifier_set;
107 }
108 else
109 key->code.sym = TERMKEY_SYM_UNKNOWN;
110
111 if(key->code.sym == TERMKEY_SYM_UNKNOWN) {
112 #ifdef DEBUG
113 fprintf(stderr, "CSI: Unknown function key %ld\n", arg[0]);
114 #endif
115 return TERMKEY_RES_NONE;
116 }
117
118 return TERMKEY_RES_KEY;
119 }
120
register_csifunc(TermKeyType type,TermKeySym sym,int number)121 static void register_csifunc(TermKeyType type, TermKeySym sym, int number)
122 {
123 if(number >= NCSIFUNCS) {
124 return;
125 }
126
127 csifuncs[number].type = type;
128 csifuncs[number].sym = sym;
129 csifuncs[number].modifier_set = 0;
130 csifuncs[number].modifier_mask = 0;
131
132 csi_handlers['~' - 0x40] = &handle_csifunc;
133 }
134
135 /*
136 * Handler for CSI u extended Unicode keys
137 */
138
handle_csi_u(TermKey * tk,TermKeyKey * key,int cmd,long * arg,int args)139 static TermKeyResult handle_csi_u(TermKey *tk, TermKeyKey *key, int cmd, long *arg, int args)
140 {
141 switch(cmd) {
142 case 'u': {
143 if(args > 1 && arg[1] != -1)
144 key->modifiers = arg[1] - 1;
145 else
146 key->modifiers = 0;
147
148 int mod = key->modifiers;
149 key->type = TERMKEY_TYPE_KEYSYM;
150 (*tk->method.emit_codepoint)(tk, arg[0], key);
151 key->modifiers |= mod;
152
153 return TERMKEY_RES_KEY;
154 }
155 default:
156 return TERMKEY_RES_NONE;
157 }
158 }
159
160 /*
161 * Handler for CSI M / CSI m mouse events in SRG and rxvt encodings
162 * Note: This does not handle X10 encoding
163 */
164
handle_csi_m(TermKey * tk,TermKeyKey * key,int cmd,long * arg,int args)165 static TermKeyResult handle_csi_m(TermKey *tk, TermKeyKey *key, int cmd, long *arg, int args)
166 {
167 int initial = cmd >> 8;
168 cmd &= 0xff;
169
170 switch(cmd) {
171 case 'M':
172 case 'm':
173 break;
174 default:
175 return TERMKEY_RES_NONE;
176 }
177
178 if(!initial && args >= 3) { // rxvt protocol
179 key->type = TERMKEY_TYPE_MOUSE;
180 key->code.mouse[0] = arg[0];
181
182 key->modifiers = (key->code.mouse[0] & 0x1c) >> 2;
183 key->code.mouse[0] &= ~0x1c;
184
185 termkey_key_set_linecol(key, arg[1], arg[2]);
186
187 return TERMKEY_RES_KEY;
188 }
189
190 if(initial == '<' && args >= 3) { // SGR protocol
191 key->type = TERMKEY_TYPE_MOUSE;
192 key->code.mouse[0] = arg[0];
193
194 key->modifiers = (key->code.mouse[0] & 0x1c) >> 2;
195 key->code.mouse[0] &= ~0x1c;
196
197 termkey_key_set_linecol(key, arg[1], arg[2]);
198
199 if(cmd == 'm') // release
200 key->code.mouse[3] |= 0x80;
201
202 return TERMKEY_RES_KEY;
203 }
204
205 return TERMKEY_RES_NONE;
206 }
207
termkey_interpret_mouse(TermKey * tk,const TermKeyKey * key,TermKeyMouseEvent * event,int * button,int * line,int * col)208 TermKeyResult termkey_interpret_mouse(TermKey *tk, const TermKeyKey *key, TermKeyMouseEvent *event, int *button, int *line, int *col)
209 {
210 if(key->type != TERMKEY_TYPE_MOUSE)
211 return TERMKEY_RES_NONE;
212
213 if(button)
214 *button = 0;
215
216 termkey_key_get_linecol(key, line, col);
217
218 if(!event)
219 return TERMKEY_RES_KEY;
220
221 int btn = 0;
222
223 int code = key->code.mouse[0];
224
225 int drag = code & 0x20;
226
227 code &= ~0x3c;
228
229 switch(code) {
230 case 0:
231 case 1:
232 case 2:
233 *event = drag ? TERMKEY_MOUSE_DRAG : TERMKEY_MOUSE_PRESS;
234 btn = code + 1;
235 break;
236
237 case 3:
238 *event = TERMKEY_MOUSE_RELEASE;
239 // no button hint
240 break;
241
242 case 64:
243 case 65:
244 *event = drag ? TERMKEY_MOUSE_DRAG : TERMKEY_MOUSE_PRESS;
245 btn = code + 4 - 64;
246 break;
247
248 default:
249 *event = TERMKEY_MOUSE_UNKNOWN;
250 }
251
252 if(button)
253 *button = btn;
254
255 if(key->code.mouse[3] & 0x80)
256 *event = TERMKEY_MOUSE_RELEASE;
257
258 return TERMKEY_RES_KEY;
259 }
260
261 /*
262 * Handler for CSI ? R position reports
263 * A plain CSI R with no arguments is probably actually <F3>
264 */
265
handle_csi_R(TermKey * tk,TermKeyKey * key,int cmd,long * arg,int args)266 static TermKeyResult handle_csi_R(TermKey *tk, TermKeyKey *key, int cmd, long *arg, int args)
267 {
268 switch(cmd) {
269 case 'R'|'?'<<8:
270 if(args < 2)
271 return TERMKEY_RES_NONE;
272
273 key->type = TERMKEY_TYPE_POSITION;
274 termkey_key_set_linecol(key, arg[1], arg[0]);
275 return TERMKEY_RES_KEY;
276
277 default:
278 return handle_csi_ss3_full(tk, key, cmd, arg, args);
279 }
280 }
281
termkey_interpret_position(TermKey * tk,const TermKeyKey * key,int * line,int * col)282 TermKeyResult termkey_interpret_position(TermKey *tk, const TermKeyKey *key, int *line, int *col)
283 {
284 if(key->type != TERMKEY_TYPE_POSITION)
285 return TERMKEY_RES_NONE;
286
287 termkey_key_get_linecol(key, line, col);
288
289 return TERMKEY_RES_KEY;
290 }
291
292 /*
293 * Handler for CSI $y mode status reports
294 */
295
handle_csi_y(TermKey * tk,TermKeyKey * key,int cmd,long * arg,int args)296 static TermKeyResult handle_csi_y(TermKey *tk, TermKeyKey *key, int cmd, long *arg, int args)
297 {
298 switch(cmd) {
299 case 'y'|'$'<<16:
300 case 'y'|'$'<<16 | '?'<<8:
301 if(args < 2)
302 return TERMKEY_RES_NONE;
303
304 key->type = TERMKEY_TYPE_MODEREPORT;
305 key->code.mouse[0] = (cmd >> 8);
306 key->code.mouse[1] = arg[0] >> 8;
307 key->code.mouse[2] = arg[0] & 0xff;
308 key->code.mouse[3] = arg[1];
309 return TERMKEY_RES_KEY;
310
311 default:
312 return TERMKEY_RES_NONE;
313 }
314 }
315
termkey_interpret_modereport(TermKey * tk,const TermKeyKey * key,int * initial,int * mode,int * value)316 TermKeyResult termkey_interpret_modereport(TermKey *tk, const TermKeyKey *key, int *initial, int *mode, int *value)
317 {
318 if(key->type != TERMKEY_TYPE_MODEREPORT)
319 return TERMKEY_RES_NONE;
320
321 if(initial)
322 *initial = key->code.mouse[0];
323
324 if(mode)
325 *mode = (key->code.mouse[1] << 8) | key->code.mouse[2];
326
327 if(value)
328 *value = key->code.mouse[3];
329
330 return TERMKEY_RES_KEY;
331 }
332
333 #define CHARAT(i) (tk->buffer[tk->buffstart + (i)])
334
parse_csi(TermKey * tk,size_t introlen,size_t * csi_len,long args[],size_t * nargs,unsigned long * commandp)335 static TermKeyResult parse_csi(TermKey *tk, size_t introlen, size_t *csi_len, long args[], size_t *nargs, unsigned long *commandp)
336 {
337 size_t csi_end = introlen;
338
339 while(csi_end < tk->buffcount) {
340 if(CHARAT(csi_end) >= 0x40 && CHARAT(csi_end) < 0x80)
341 break;
342 csi_end++;
343 }
344
345 if(csi_end >= tk->buffcount)
346 return TERMKEY_RES_AGAIN;
347
348 unsigned char cmd = CHARAT(csi_end);
349 *commandp = cmd;
350
351 char present = 0;
352 int argi = 0;
353
354 size_t p = introlen;
355
356 // See if there is an initial byte
357 if(CHARAT(p) >= '<' && CHARAT(p) <= '?') {
358 *commandp |= (CHARAT(p) << 8);
359 p++;
360 }
361
362 // Now attempt to parse out up number;number;... separated values
363 while(p < csi_end) {
364 unsigned char c = CHARAT(p);
365
366 if(c >= '0' && c <= '9') {
367 if(!present) {
368 args[argi] = c - '0';
369 present = 1;
370 }
371 else {
372 args[argi] = (args[argi] * 10) + c - '0';
373 }
374 }
375 else if(c == ';') {
376 if(!present)
377 args[argi] = -1;
378 present = 0;
379 argi++;
380
381 if(argi > 16)
382 break;
383 }
384 else if(c >= 0x20 && c <= 0x2f) {
385 *commandp |= c << 16;
386 break;
387 }
388
389 p++;
390 }
391
392 if(present)
393 argi++;
394
395 *nargs = argi;
396 *csi_len = csi_end + 1;
397
398 return TERMKEY_RES_KEY;
399 }
400
termkey_interpret_csi(TermKey * tk,const TermKeyKey * key,long args[],size_t * nargs,unsigned long * cmd)401 TermKeyResult termkey_interpret_csi(TermKey *tk, const TermKeyKey *key, long args[], size_t *nargs, unsigned long *cmd)
402 {
403 size_t dummy;
404
405 if(tk->hightide == 0)
406 return TERMKEY_RES_NONE;
407 if(key->type != TERMKEY_TYPE_UNKNOWN_CSI)
408 return TERMKEY_RES_NONE;
409
410 return parse_csi(tk, 0, &dummy, args, nargs, cmd);
411 }
412
register_keys(void)413 static int register_keys(void)
414 {
415 int i;
416
417 for(i = 0; i < 64; i++) {
418 csi_ss3s[i].sym = TERMKEY_SYM_UNKNOWN;
419 ss3s[i].sym = TERMKEY_SYM_UNKNOWN;
420 ss3_kpalts[i] = 0;
421 }
422
423 for(i = 0; i < NCSIFUNCS; i++)
424 csifuncs[i].sym = TERMKEY_SYM_UNKNOWN;
425
426 register_csi_ss3(TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_UP, 'A');
427 register_csi_ss3(TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_DOWN, 'B');
428 register_csi_ss3(TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_RIGHT, 'C');
429 register_csi_ss3(TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_LEFT, 'D');
430 register_csi_ss3(TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_BEGIN, 'E');
431 register_csi_ss3(TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_END, 'F');
432 register_csi_ss3(TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_HOME, 'H');
433 register_csi_ss3(TERMKEY_TYPE_FUNCTION, 1, 'P');
434 register_csi_ss3(TERMKEY_TYPE_FUNCTION, 2, 'Q');
435 register_csi_ss3(TERMKEY_TYPE_FUNCTION, 3, 'R');
436 register_csi_ss3(TERMKEY_TYPE_FUNCTION, 4, 'S');
437
438 register_csi_ss3_full(TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_TAB, TERMKEY_KEYMOD_SHIFT, TERMKEY_KEYMOD_SHIFT, 'Z');
439
440 register_ss3kpalt(TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_KPENTER, 'M', 0);
441 register_ss3kpalt(TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_KPEQUALS, 'X', '=');
442 register_ss3kpalt(TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_KPMULT, 'j', '*');
443 register_ss3kpalt(TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_KPPLUS, 'k', '+');
444 register_ss3kpalt(TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_KPCOMMA, 'l', ',');
445 register_ss3kpalt(TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_KPMINUS, 'm', '-');
446 register_ss3kpalt(TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_KPPERIOD, 'n', '.');
447 register_ss3kpalt(TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_KPDIV, 'o', '/');
448 register_ss3kpalt(TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_KP0, 'p', '0');
449 register_ss3kpalt(TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_KP1, 'q', '1');
450 register_ss3kpalt(TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_KP2, 'r', '2');
451 register_ss3kpalt(TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_KP3, 's', '3');
452 register_ss3kpalt(TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_KP4, 't', '4');
453 register_ss3kpalt(TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_KP5, 'u', '5');
454 register_ss3kpalt(TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_KP6, 'v', '6');
455 register_ss3kpalt(TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_KP7, 'w', '7');
456 register_ss3kpalt(TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_KP8, 'x', '8');
457 register_ss3kpalt(TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_KP9, 'y', '9');
458
459 register_csifunc(TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_FIND, 1);
460 register_csifunc(TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_INSERT, 2);
461 register_csifunc(TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_DELETE, 3);
462 register_csifunc(TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_SELECT, 4);
463 register_csifunc(TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_PAGEUP, 5);
464 register_csifunc(TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_PAGEDOWN, 6);
465 register_csifunc(TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_HOME, 7);
466 register_csifunc(TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_END, 8);
467
468 register_csifunc(TERMKEY_TYPE_FUNCTION, 1, 11);
469 register_csifunc(TERMKEY_TYPE_FUNCTION, 2, 12);
470 register_csifunc(TERMKEY_TYPE_FUNCTION, 3, 13);
471 register_csifunc(TERMKEY_TYPE_FUNCTION, 4, 14);
472 register_csifunc(TERMKEY_TYPE_FUNCTION, 5, 15);
473 register_csifunc(TERMKEY_TYPE_FUNCTION, 6, 17);
474 register_csifunc(TERMKEY_TYPE_FUNCTION, 7, 18);
475 register_csifunc(TERMKEY_TYPE_FUNCTION, 8, 19);
476 register_csifunc(TERMKEY_TYPE_FUNCTION, 9, 20);
477 register_csifunc(TERMKEY_TYPE_FUNCTION, 10, 21);
478 register_csifunc(TERMKEY_TYPE_FUNCTION, 11, 23);
479 register_csifunc(TERMKEY_TYPE_FUNCTION, 12, 24);
480 register_csifunc(TERMKEY_TYPE_FUNCTION, 13, 25);
481 register_csifunc(TERMKEY_TYPE_FUNCTION, 14, 26);
482 register_csifunc(TERMKEY_TYPE_FUNCTION, 15, 28);
483 register_csifunc(TERMKEY_TYPE_FUNCTION, 16, 29);
484 register_csifunc(TERMKEY_TYPE_FUNCTION, 17, 31);
485 register_csifunc(TERMKEY_TYPE_FUNCTION, 18, 32);
486 register_csifunc(TERMKEY_TYPE_FUNCTION, 19, 33);
487 register_csifunc(TERMKEY_TYPE_FUNCTION, 20, 34);
488
489 csi_handlers['u' - 0x40] = &handle_csi_u;
490
491 csi_handlers['M' - 0x40] = &handle_csi_m;
492 csi_handlers['m' - 0x40] = &handle_csi_m;
493
494 csi_handlers['R' - 0x40] = &handle_csi_R;
495
496 csi_handlers['y' - 0x40] = &handle_csi_y;
497
498 keyinfo_initialised = 1;
499 return 1;
500 }
501
new_driver(TermKey * tk,const char * term)502 static void *new_driver(TermKey *tk, const char *term)
503 {
504 if(!keyinfo_initialised)
505 if(!register_keys())
506 return NULL;
507
508 TermKeyCsi *csi = malloc(sizeof *csi);
509 if(!csi)
510 return NULL;
511
512 csi->tk = tk;
513 csi->saved_string_id = 0;
514 csi->saved_string = NULL;
515
516 return csi;
517 }
518
free_driver(void * info)519 static void free_driver(void *info)
520 {
521 TermKeyCsi *csi = info;
522
523 if(csi->saved_string)
524 free(csi->saved_string);
525
526 free(csi);
527 }
528
peekkey_csi(TermKey * tk,TermKeyCsi * csi,size_t introlen,TermKeyKey * key,int force,size_t * nbytep)529 static TermKeyResult peekkey_csi(TermKey *tk, TermKeyCsi *csi, size_t introlen, TermKeyKey *key, int force, size_t *nbytep)
530 {
531 size_t csi_len;
532 size_t args = 16;
533 long arg[16];
534 unsigned long cmd;
535
536 TermKeyResult ret = parse_csi(tk, introlen, &csi_len, arg, &args, &cmd);
537
538 if(ret == TERMKEY_RES_AGAIN) {
539 if(!force)
540 return TERMKEY_RES_AGAIN;
541
542 (*tk->method.emit_codepoint)(tk, '[', key);
543 key->modifiers |= TERMKEY_KEYMOD_ALT;
544 *nbytep = introlen;
545 return TERMKEY_RES_KEY;
546 }
547
548 if(cmd == 'M' && args < 3) { // Mouse in X10 encoding consumes the next 3 bytes also
549 tk->buffstart += csi_len;
550 tk->buffcount -= csi_len;
551
552 TermKeyResult mouse_result = (*tk->method.peekkey_mouse)(tk, key, nbytep);
553
554 tk->buffstart -= csi_len;
555 tk->buffcount += csi_len;
556
557 if(mouse_result == TERMKEY_RES_KEY)
558 *nbytep += csi_len;
559
560 return mouse_result;
561 }
562
563 TermKeyResult result = TERMKEY_RES_NONE;
564
565 // We know from the logic above that cmd must be >= 0x40 and < 0x80
566 if(csi_handlers[(cmd & 0xff) - 0x40])
567 result = (*csi_handlers[(cmd & 0xff) - 0x40])(tk, key, cmd, arg, args);
568
569 if(result == TERMKEY_RES_NONE) {
570 #ifdef DEBUG
571 switch(args) {
572 case 1:
573 fprintf(stderr, "CSI: Unknown arg1=%ld cmd=%c\n", arg[0], (char)cmd);
574 break;
575 case 2:
576 fprintf(stderr, "CSI: Unknown arg1=%ld arg2=%ld cmd=%c\n", arg[0], arg[1], (char)cmd);
577 break;
578 case 3:
579 fprintf(stderr, "CSI: Unknown arg1=%ld arg2=%ld arg3=%ld cmd=%c\n", arg[0], arg[1], arg[2], (char)cmd);
580 break;
581 default:
582 fprintf(stderr, "CSI: Unknown arg1=%ld arg2=%ld arg3=%ld ... args=%d cmd=%c\n", arg[0], arg[1], arg[2], args, (char)cmd);
583 break;
584 }
585 #endif
586 key->type = TERMKEY_TYPE_UNKNOWN_CSI;
587 key->code.number = cmd;
588
589 tk->hightide = csi_len - introlen;
590 *nbytep = introlen; // Do not yet eat the data bytes
591 return TERMKEY_RES_KEY;
592 }
593
594 *nbytep = csi_len;
595 return result;
596 }
597
peekkey_ss3(TermKey * tk,TermKeyCsi * csi,size_t introlen,TermKeyKey * key,int force,size_t * nbytep)598 static TermKeyResult peekkey_ss3(TermKey *tk, TermKeyCsi *csi, size_t introlen, TermKeyKey *key, int force, size_t *nbytep)
599 {
600 if(tk->buffcount < introlen + 1) {
601 if(!force)
602 return TERMKEY_RES_AGAIN;
603
604 (*tk->method.emit_codepoint)(tk, 'O', key);
605 key->modifiers |= TERMKEY_KEYMOD_ALT;
606 *nbytep = tk->buffcount;
607 return TERMKEY_RES_KEY;
608 }
609
610 unsigned char cmd = CHARAT(introlen);
611
612 if(cmd < 0x40 || cmd >= 0x80)
613 return TERMKEY_RES_NONE;
614
615 key->type = csi_ss3s[cmd - 0x40].type;
616 key->code.sym = csi_ss3s[cmd - 0x40].sym;
617 key->modifiers = csi_ss3s[cmd - 0x40].modifier_set;
618
619 if(key->code.sym == TERMKEY_SYM_UNKNOWN) {
620 if(tk->flags & TERMKEY_FLAG_CONVERTKP && ss3_kpalts[cmd - 0x40]) {
621 key->type = TERMKEY_TYPE_UNICODE;
622 key->code.codepoint = ss3_kpalts[cmd - 0x40];
623 key->modifiers = 0;
624
625 key->utf8[0] = key->code.codepoint;
626 key->utf8[1] = 0;
627 }
628 else {
629 key->type = ss3s[cmd - 0x40].type;
630 key->code.sym = ss3s[cmd - 0x40].sym;
631 key->modifiers = ss3s[cmd - 0x40].modifier_set;
632 }
633 }
634
635 if(key->code.sym == TERMKEY_SYM_UNKNOWN) {
636 #ifdef DEBUG
637 fprintf(stderr, "CSI: Unknown SS3 %c (0x%02x)\n", (char)cmd, cmd);
638 #endif
639 return TERMKEY_RES_NONE;
640 }
641
642 *nbytep = introlen + 1;
643
644 return TERMKEY_RES_KEY;
645 }
646
peekkey_ctrlstring(TermKey * tk,TermKeyCsi * csi,size_t introlen,TermKeyKey * key,int force,size_t * nbytep)647 static TermKeyResult peekkey_ctrlstring(TermKey *tk, TermKeyCsi *csi, size_t introlen, TermKeyKey *key, int force, size_t *nbytep)
648 {
649 size_t str_end = introlen;
650
651 while(str_end < tk->buffcount) {
652 if(CHARAT(str_end) == 0x9c) // ST
653 break;
654 if(CHARAT(str_end) == 0x1b &&
655 (str_end + 1) < tk->buffcount &&
656 CHARAT(str_end+1) == 0x5c) // ESC-prefixed ST
657 break;
658
659 str_end++;
660 }
661
662 if(str_end >= tk->buffcount)
663 return TERMKEY_RES_AGAIN;
664
665 #ifdef DEBUG
666 fprintf(stderr, "Found a control string: %*s",
667 str_end - introlen, tk->buffer + tk->buffstart + introlen);
668 #endif
669
670 *nbytep = str_end + 1;
671 if(CHARAT(str_end) == 0x1b)
672 (*nbytep)++;
673
674 if(csi->saved_string)
675 free(csi->saved_string);
676
677 size_t len = str_end - introlen;
678
679 csi->saved_string_id++;
680 csi->saved_string = malloc(len + 1);
681
682 strncpy(csi->saved_string, (char *)tk->buffer + tk->buffstart + introlen, len);
683 csi->saved_string[len] = 0;
684
685 key->type = (CHARAT(introlen-1) & 0x1f) == 0x10 ?
686 TERMKEY_TYPE_DCS : TERMKEY_TYPE_OSC;
687 key->code.number = csi->saved_string_id;
688 key->modifiers = 0;
689
690 return TERMKEY_RES_KEY;
691 }
692
peekkey(TermKey * tk,void * info,TermKeyKey * key,int force,size_t * nbytep)693 static TermKeyResult peekkey(TermKey *tk, void *info, TermKeyKey *key, int force, size_t *nbytep)
694 {
695 if(tk->buffcount == 0)
696 return tk->is_closed ? TERMKEY_RES_EOF : TERMKEY_RES_NONE;
697
698 TermKeyCsi *csi = info;
699
700 switch(CHARAT(0)) {
701 case 0x1b:
702 if(tk->buffcount < 2)
703 return TERMKEY_RES_NONE;
704
705 switch(CHARAT(1)) {
706 case 0x4f: // ESC-prefixed SS3
707 return peekkey_ss3(tk, csi, 2, key, force, nbytep);
708
709 case 0x50: // ESC-prefixed DCS
710 case 0x5d: // ESC-prefixed OSC
711 return peekkey_ctrlstring(tk, csi, 2, key, force, nbytep);
712
713 case 0x5b: // ESC-prefixed CSI
714 return peekkey_csi(tk, csi, 2, key, force, nbytep);
715 }
716
717 return TERMKEY_RES_NONE;
718
719 case 0x8f: // SS3
720 return peekkey_ss3(tk, csi, 1, key, force, nbytep);
721
722 case 0x90: // DCS
723 case 0x9d: // OSC
724 return peekkey_ctrlstring(tk, csi, 1, key, force, nbytep);
725
726 case 0x9b: // CSI
727 return peekkey_csi(tk, csi, 1, key, force, nbytep);
728 }
729
730 return TERMKEY_RES_NONE;
731 }
732
733 struct TermKeyDriver termkey_driver_csi = {
734 .name = "CSI",
735
736 .new_driver = new_driver,
737 .free_driver = free_driver,
738
739 .peekkey = peekkey,
740 };
741
termkey_interpret_string(TermKey * tk,const TermKeyKey * key,const char ** strp)742 TermKeyResult termkey_interpret_string(TermKey *tk, const TermKeyKey *key, const char **strp)
743 {
744 struct TermKeyDriverNode *p;
745 for(p = tk->drivers; p; p = p->next)
746 if(p->driver == &termkey_driver_csi)
747 break;
748
749 if(!p)
750 return TERMKEY_RES_NONE;
751
752 if(key->type != TERMKEY_TYPE_DCS &&
753 key->type != TERMKEY_TYPE_OSC)
754 return TERMKEY_RES_NONE;
755
756 TermKeyCsi *csi = p->info;
757
758 if(csi->saved_string_id != key->code.number)
759 return TERMKEY_RES_NONE;
760
761 *strp = csi->saved_string;
762
763 return TERMKEY_RES_KEY;
764 }
765