1 #include "escape.hxx"
2 #include "terminal.hxx"
3 #include "replxx.hxx"
4
5 #ifndef _WIN32
6
7 namespace replxx {
8
9 namespace EscapeSequenceProcessing { // move these out of global namespace
10
11 // This chunk of code does parsing of the escape sequences sent by various Linux
12 // terminals.
13 //
14 // It handles arrow keys, Home, End and Delete keys by interpreting the
15 // sequences sent by
16 // gnome terminal, xterm, rxvt, konsole, aterm and yakuake including the Alt and
17 // Ctrl key
18 // combinations that are understood by replxx.
19 //
20 // The parsing uses tables, a bunch of intermediate dispatch routines and a
21 // doDispatch
22 // loop that reads the tables and sends control to "deeper" routines to continue
23 // the
24 // parsing. The starting call to doDispatch( c, initialDispatch ) will
25 // eventually return
26 // either a character (with optional CTRL and META bits set), or -1 if parsing
27 // fails, or
28 // zero if an attempt to read from the keyboard fails.
29 //
30 // This is rather sloppy escape sequence processing, since we're not paying
31 // attention to what the
32 // actual TERM is set to and are processing all key sequences for all terminals,
33 // but it works with
34 // the most common keystrokes on the most common terminals. It's intricate, but
35 // the nested 'if'
36 // statements required to do it directly would be worse. This way has the
37 // advantage of allowing
38 // changes and extensions without having to touch a lot of code.
39
40
41 static char32_t thisKeyMetaCtrl = 0; // holds pre-set Meta and/or Ctrl modifiers
42
43 // This dispatch routine is given a dispatch table and then farms work out to
44 // routines
45 // listed in the table based on the character it is called with. The dispatch
46 // routines can
47 // read more input characters to decide what should eventually be returned.
48 // Eventually,
49 // a called routine returns either a character or -1 to indicate parsing
50 // failure.
51 //
doDispatch(char32_t c,CharacterDispatch & dispatchTable)52 char32_t doDispatch(char32_t c, CharacterDispatch& dispatchTable) {
53 for (unsigned int i = 0; i < dispatchTable.len; ++i) {
54 if (static_cast<unsigned char>(dispatchTable.chars[i]) == c) {
55 return dispatchTable.dispatch[i](c);
56 }
57 }
58 return dispatchTable.dispatch[dispatchTable.len](c);
59 }
60
61 // Final dispatch routines -- return something
62 //
normalKeyRoutine(char32_t c)63 static char32_t normalKeyRoutine(char32_t c) { return thisKeyMetaCtrl | c; }
upArrowKeyRoutine(char32_t)64 static char32_t upArrowKeyRoutine(char32_t) {
65 return thisKeyMetaCtrl | Replxx::KEY::UP;;
66 }
downArrowKeyRoutine(char32_t)67 static char32_t downArrowKeyRoutine(char32_t) {
68 return thisKeyMetaCtrl | Replxx::KEY::DOWN;
69 }
rightArrowKeyRoutine(char32_t)70 static char32_t rightArrowKeyRoutine(char32_t) {
71 return thisKeyMetaCtrl | Replxx::KEY::RIGHT;
72 }
leftArrowKeyRoutine(char32_t)73 static char32_t leftArrowKeyRoutine(char32_t) {
74 return thisKeyMetaCtrl | Replxx::KEY::LEFT;
75 }
homeKeyRoutine(char32_t)76 static char32_t homeKeyRoutine(char32_t) { return thisKeyMetaCtrl | Replxx::KEY::HOME; }
endKeyRoutine(char32_t)77 static char32_t endKeyRoutine(char32_t) { return thisKeyMetaCtrl | Replxx::KEY::END; }
shiftTabRoutine(char32_t)78 static char32_t shiftTabRoutine(char32_t) { return Replxx::KEY::BASE_SHIFT | Replxx::KEY::TAB; }
f1KeyRoutine(char32_t)79 static char32_t f1KeyRoutine(char32_t) { return thisKeyMetaCtrl | Replxx::KEY::F1; }
f2KeyRoutine(char32_t)80 static char32_t f2KeyRoutine(char32_t) { return thisKeyMetaCtrl | Replxx::KEY::F2; }
f3KeyRoutine(char32_t)81 static char32_t f3KeyRoutine(char32_t) { return thisKeyMetaCtrl | Replxx::KEY::F3; }
f4KeyRoutine(char32_t)82 static char32_t f4KeyRoutine(char32_t) { return thisKeyMetaCtrl | Replxx::KEY::F4; }
f5KeyRoutine(char32_t)83 static char32_t f5KeyRoutine(char32_t) { return thisKeyMetaCtrl | Replxx::KEY::F5; }
f6KeyRoutine(char32_t)84 static char32_t f6KeyRoutine(char32_t) { return thisKeyMetaCtrl | Replxx::KEY::F6; }
f7KeyRoutine(char32_t)85 static char32_t f7KeyRoutine(char32_t) { return thisKeyMetaCtrl | Replxx::KEY::F7; }
f8KeyRoutine(char32_t)86 static char32_t f8KeyRoutine(char32_t) { return thisKeyMetaCtrl | Replxx::KEY::F8; }
f9KeyRoutine(char32_t)87 static char32_t f9KeyRoutine(char32_t) { return thisKeyMetaCtrl | Replxx::KEY::F9; }
f10KeyRoutine(char32_t)88 static char32_t f10KeyRoutine(char32_t) { return thisKeyMetaCtrl | Replxx::KEY::F10; }
f11KeyRoutine(char32_t)89 static char32_t f11KeyRoutine(char32_t) { return thisKeyMetaCtrl | Replxx::KEY::F11; }
f12KeyRoutine(char32_t)90 static char32_t f12KeyRoutine(char32_t) { return thisKeyMetaCtrl | Replxx::KEY::F12; }
pageUpKeyRoutine(char32_t)91 static char32_t pageUpKeyRoutine(char32_t) {
92 return thisKeyMetaCtrl | Replxx::KEY::PAGE_UP;
93 }
pageDownKeyRoutine(char32_t)94 static char32_t pageDownKeyRoutine(char32_t) {
95 return thisKeyMetaCtrl | Replxx::KEY::PAGE_DOWN;
96 }
deleteCharRoutine(char32_t)97 static char32_t deleteCharRoutine(char32_t) {
98 return thisKeyMetaCtrl | Replxx::KEY::BACKSPACE;
99 } // key labeled Backspace
insertKeyRoutine(char32_t)100 static char32_t insertKeyRoutine(char32_t) {
101 return thisKeyMetaCtrl | Replxx::KEY::INSERT;
102 } // key labeled Delete
deleteKeyRoutine(char32_t)103 static char32_t deleteKeyRoutine(char32_t) {
104 return thisKeyMetaCtrl | Replxx::KEY::DELETE;
105 } // key labeled Delete
ctrlUpArrowKeyRoutine(char32_t)106 static char32_t ctrlUpArrowKeyRoutine(char32_t) {
107 return thisKeyMetaCtrl | Replxx::KEY::BASE_CONTROL | Replxx::KEY::UP;
108 }
ctrlDownArrowKeyRoutine(char32_t)109 static char32_t ctrlDownArrowKeyRoutine(char32_t) {
110 return thisKeyMetaCtrl | Replxx::KEY::BASE_CONTROL | Replxx::KEY::DOWN;
111 }
ctrlRightArrowKeyRoutine(char32_t)112 static char32_t ctrlRightArrowKeyRoutine(char32_t) {
113 return thisKeyMetaCtrl | Replxx::KEY::BASE_CONTROL | Replxx::KEY::RIGHT;
114 }
ctrlLeftArrowKeyRoutine(char32_t)115 static char32_t ctrlLeftArrowKeyRoutine(char32_t) {
116 return thisKeyMetaCtrl | Replxx::KEY::BASE_CONTROL | Replxx::KEY::LEFT;
117 }
bracketPasteStartKeyRoutine(char32_t)118 static char32_t bracketPasteStartKeyRoutine(char32_t) {
119 return thisKeyMetaCtrl | Replxx::KEY::PASTE_START;
120 }
bracketPasteFinishKeyRoutine(char32_t)121 static char32_t bracketPasteFinishKeyRoutine(char32_t) {
122 return thisKeyMetaCtrl | Replxx::KEY::PASTE_FINISH;
123 }
escFailureRoutine(char32_t)124 static char32_t escFailureRoutine(char32_t) {
125 beep();
126 return -1;
127 }
128
129 // Handle ESC [ 1 ; 2 or 3 (or 5) <more stuff> escape sequences
130 //
131 static CharacterDispatchRoutine escLeftBracket1Semicolon2or3or5Routines[] = {
132 upArrowKeyRoutine,
133 downArrowKeyRoutine,
134 rightArrowKeyRoutine,
135 leftArrowKeyRoutine,
136 homeKeyRoutine,
137 endKeyRoutine,
138 f1KeyRoutine,
139 f2KeyRoutine,
140 f3KeyRoutine,
141 f4KeyRoutine,
142 escFailureRoutine
143 };
144 static CharacterDispatch escLeftBracket1Semicolon2or3or5Dispatch = {
145 10, "ABCDHFPQRS", escLeftBracket1Semicolon2or3or5Routines
146 };
147
148 // Handle ESC [ 1 ; <more stuff> escape sequences
149 //
escLeftBracket1Semicolon2Routine(char32_t c)150 static char32_t escLeftBracket1Semicolon2Routine(char32_t c) {
151 c = read_unicode_character();
152 if (c == 0) return 0;
153 thisKeyMetaCtrl |= Replxx::KEY::BASE_SHIFT;
154 return doDispatch(c, escLeftBracket1Semicolon2or3or5Dispatch);
155 }
escLeftBracket1Semicolon3Routine(char32_t c)156 static char32_t escLeftBracket1Semicolon3Routine(char32_t c) {
157 c = read_unicode_character();
158 if (c == 0) return 0;
159 thisKeyMetaCtrl |= Replxx::KEY::BASE_META;
160 return doDispatch(c, escLeftBracket1Semicolon2or3or5Dispatch);
161 }
escLeftBracket1Semicolon5Routine(char32_t c)162 static char32_t escLeftBracket1Semicolon5Routine(char32_t c) {
163 c = read_unicode_character();
164 if (c == 0) return 0;
165 thisKeyMetaCtrl |= Replxx::KEY::BASE_CONTROL;
166 return doDispatch(c, escLeftBracket1Semicolon2or3or5Dispatch);
167 }
168 static CharacterDispatchRoutine escLeftBracket1SemicolonRoutines[] = {
169 escLeftBracket1Semicolon2Routine,
170 escLeftBracket1Semicolon3Routine,
171 escLeftBracket1Semicolon5Routine,
172 escFailureRoutine
173 };
174 static CharacterDispatch escLeftBracket1SemicolonDispatch = {
175 3, "235", escLeftBracket1SemicolonRoutines
176 };
177
178 // Handle ESC [ 1 ; <more stuff> escape sequences
179 //
escLeftBracket1SemicolonRoutine(char32_t c)180 static char32_t escLeftBracket1SemicolonRoutine(char32_t c) {
181 c = read_unicode_character();
182 if (c == 0) return 0;
183 return doDispatch(c, escLeftBracket1SemicolonDispatch);
184 }
185
186 // (S)-F5
187 static CharacterDispatchRoutine escLeftBracket15Semicolon2Routines[] = {
188 f5KeyRoutine, escFailureRoutine
189 };
190 static CharacterDispatch escLeftBracket15Semicolon2Dispatch = {
191 1, "~", escLeftBracket15Semicolon2Routines
192 };
escLeftBracket15Semicolon2Routine(char32_t c)193 static char32_t escLeftBracket15Semicolon2Routine(char32_t c) {
194 c = read_unicode_character();
195 if (c == 0) return 0;
196 thisKeyMetaCtrl |= Replxx::KEY::BASE_SHIFT;
197 return doDispatch(c, escLeftBracket15Semicolon2Dispatch);
198 }
199
200 // (C)-F5
201 static CharacterDispatchRoutine escLeftBracket15Semicolon5Routines[] = {
202 f5KeyRoutine, escFailureRoutine
203 };
204 static CharacterDispatch escLeftBracket15Semicolon5Dispatch = {
205 1, "~", escLeftBracket15Semicolon5Routines
206 };
escLeftBracket15Semicolon5Routine(char32_t c)207 static char32_t escLeftBracket15Semicolon5Routine(char32_t c) {
208 c = read_unicode_character();
209 if (c == 0) return 0;
210 thisKeyMetaCtrl |= Replxx::KEY::BASE_CONTROL;
211 return doDispatch(c, escLeftBracket15Semicolon5Dispatch);
212 }
213
214 static CharacterDispatchRoutine escLeftBracket15SemicolonRoutines[] = {
215 escLeftBracket15Semicolon2Routine, escLeftBracket15Semicolon5Routine, escFailureRoutine
216 };
217 static CharacterDispatch escLeftBracket15SemicolonDispatch = {
218 2, "25", escLeftBracket15SemicolonRoutines
219 };
escLeftBracket15SemicolonRoutine(char32_t c)220 static char32_t escLeftBracket15SemicolonRoutine(char32_t c) {
221 c = read_unicode_character();
222 if (c == 0) return 0;
223 return doDispatch(c, escLeftBracket15SemicolonDispatch);
224 }
225
226 static CharacterDispatchRoutine escLeftBracket15Routines[] = {
227 f5KeyRoutine, escLeftBracket15SemicolonRoutine, escFailureRoutine
228 };
229 static CharacterDispatch escLeftBracket15Dispatch = {
230 2, "~;", escLeftBracket15Routines
231 };
escLeftBracket15Routine(char32_t c)232 static char32_t escLeftBracket15Routine(char32_t c) {
233 c = read_unicode_character();
234 if (c == 0) return 0;
235 return doDispatch(c, escLeftBracket15Dispatch);
236 }
237
238 // (S)-F6
239 static CharacterDispatchRoutine escLeftBracket17Semicolon2Routines[] = {
240 f6KeyRoutine, escFailureRoutine
241 };
242 static CharacterDispatch escLeftBracket17Semicolon2Dispatch = {
243 1, "~", escLeftBracket17Semicolon2Routines
244 };
escLeftBracket17Semicolon2Routine(char32_t c)245 static char32_t escLeftBracket17Semicolon2Routine(char32_t c) {
246 c = read_unicode_character();
247 if (c == 0) return 0;
248 thisKeyMetaCtrl |= Replxx::KEY::BASE_SHIFT;
249 return doDispatch(c, escLeftBracket17Semicolon2Dispatch);
250 }
251
252 // (C)-F6
253 static CharacterDispatchRoutine escLeftBracket17Semicolon5Routines[] = {
254 f6KeyRoutine, escFailureRoutine
255 };
256 static CharacterDispatch escLeftBracket17Semicolon5Dispatch = {
257 1, "~", escLeftBracket17Semicolon5Routines
258 };
escLeftBracket17Semicolon5Routine(char32_t c)259 static char32_t escLeftBracket17Semicolon5Routine(char32_t c) {
260 c = read_unicode_character();
261 if (c == 0) return 0;
262 thisKeyMetaCtrl |= Replxx::KEY::BASE_CONTROL;
263 return doDispatch(c, escLeftBracket17Semicolon5Dispatch);
264 }
265
266 static CharacterDispatchRoutine escLeftBracket17SemicolonRoutines[] = {
267 escLeftBracket17Semicolon2Routine, escLeftBracket17Semicolon5Routine, escFailureRoutine
268 };
269 static CharacterDispatch escLeftBracket17SemicolonDispatch = {
270 2, "25", escLeftBracket17SemicolonRoutines
271 };
escLeftBracket17SemicolonRoutine(char32_t c)272 static char32_t escLeftBracket17SemicolonRoutine(char32_t c) {
273 c = read_unicode_character();
274 if (c == 0) return 0;
275 return doDispatch(c, escLeftBracket17SemicolonDispatch);
276 }
277
278 static CharacterDispatchRoutine escLeftBracket17Routines[] = {
279 f6KeyRoutine, escLeftBracket17SemicolonRoutine, escFailureRoutine
280 };
281 static CharacterDispatch escLeftBracket17Dispatch = {
282 2, "~;", escLeftBracket17Routines
283 };
escLeftBracket17Routine(char32_t c)284 static char32_t escLeftBracket17Routine(char32_t c) {
285 c = read_unicode_character();
286 if (c == 0) return 0;
287 return doDispatch(c, escLeftBracket17Dispatch);
288 }
289
290 // (S)-F7
291 static CharacterDispatchRoutine escLeftBracket18Semicolon2Routines[] = {
292 f7KeyRoutine, escFailureRoutine
293 };
294 static CharacterDispatch escLeftBracket18Semicolon2Dispatch = {
295 1, "~", escLeftBracket18Semicolon2Routines
296 };
escLeftBracket18Semicolon2Routine(char32_t c)297 static char32_t escLeftBracket18Semicolon2Routine(char32_t c) {
298 c = read_unicode_character();
299 if (c == 0) return 0;
300 thisKeyMetaCtrl |= Replxx::KEY::BASE_SHIFT;
301 return doDispatch(c, escLeftBracket18Semicolon2Dispatch);
302 }
303
304 // (C)-F7
305 static CharacterDispatchRoutine escLeftBracket18Semicolon5Routines[] = {
306 f7KeyRoutine, escFailureRoutine
307 };
308 static CharacterDispatch escLeftBracket18Semicolon5Dispatch = {
309 1, "~", escLeftBracket18Semicolon5Routines
310 };
escLeftBracket18Semicolon5Routine(char32_t c)311 static char32_t escLeftBracket18Semicolon5Routine(char32_t c) {
312 c = read_unicode_character();
313 if (c == 0) return 0;
314 thisKeyMetaCtrl |= Replxx::KEY::BASE_CONTROL;
315 return doDispatch(c, escLeftBracket18Semicolon5Dispatch);
316 }
317
318 static CharacterDispatchRoutine escLeftBracket18SemicolonRoutines[] = {
319 escLeftBracket18Semicolon2Routine, escLeftBracket18Semicolon5Routine, escFailureRoutine
320 };
321 static CharacterDispatch escLeftBracket18SemicolonDispatch = {
322 2, "25", escLeftBracket18SemicolonRoutines
323 };
escLeftBracket18SemicolonRoutine(char32_t c)324 static char32_t escLeftBracket18SemicolonRoutine(char32_t c) {
325 c = read_unicode_character();
326 if (c == 0) return 0;
327 return doDispatch(c, escLeftBracket18SemicolonDispatch);
328 }
329
330 static CharacterDispatchRoutine escLeftBracket18Routines[] = {
331 f7KeyRoutine, escLeftBracket18SemicolonRoutine, escFailureRoutine
332 };
333 static CharacterDispatch escLeftBracket18Dispatch = {
334 2, "~;", escLeftBracket18Routines
335 };
escLeftBracket18Routine(char32_t c)336 static char32_t escLeftBracket18Routine(char32_t c) {
337 c = read_unicode_character();
338 if (c == 0) return 0;
339 return doDispatch(c, escLeftBracket18Dispatch);
340 }
341
342 // (S)-F8
343 static CharacterDispatchRoutine escLeftBracket19Semicolon2Routines[] = {
344 f8KeyRoutine, escFailureRoutine
345 };
346 static CharacterDispatch escLeftBracket19Semicolon2Dispatch = {
347 1, "~", escLeftBracket19Semicolon2Routines
348 };
escLeftBracket19Semicolon2Routine(char32_t c)349 static char32_t escLeftBracket19Semicolon2Routine(char32_t c) {
350 c = read_unicode_character();
351 if (c == 0) return 0;
352 thisKeyMetaCtrl |= Replxx::KEY::BASE_SHIFT;
353 return doDispatch(c, escLeftBracket19Semicolon2Dispatch);
354 }
355
356 // (C)-F8
357 static CharacterDispatchRoutine escLeftBracket19Semicolon5Routines[] = {
358 f8KeyRoutine, escFailureRoutine
359 };
360 static CharacterDispatch escLeftBracket19Semicolon5Dispatch = {
361 1, "~", escLeftBracket19Semicolon5Routines
362 };
escLeftBracket19Semicolon5Routine(char32_t c)363 static char32_t escLeftBracket19Semicolon5Routine(char32_t c) {
364 c = read_unicode_character();
365 if (c == 0) return 0;
366 thisKeyMetaCtrl |= Replxx::KEY::BASE_CONTROL;
367 return doDispatch(c, escLeftBracket19Semicolon5Dispatch);
368 }
369
370 static CharacterDispatchRoutine escLeftBracket19SemicolonRoutines[] = {
371 escLeftBracket19Semicolon2Routine, escLeftBracket19Semicolon5Routine, escFailureRoutine
372 };
373 static CharacterDispatch escLeftBracket19SemicolonDispatch = {
374 2, "25", escLeftBracket19SemicolonRoutines
375 };
escLeftBracket19SemicolonRoutine(char32_t c)376 static char32_t escLeftBracket19SemicolonRoutine(char32_t c) {
377 c = read_unicode_character();
378 if (c == 0) return 0;
379 return doDispatch(c, escLeftBracket19SemicolonDispatch);
380 }
381
382 static CharacterDispatchRoutine escLeftBracket19Routines[] = {
383 f8KeyRoutine, escLeftBracket19SemicolonRoutine, escFailureRoutine
384 };
385 static CharacterDispatch escLeftBracket19Dispatch = {
386 2, "~;", escLeftBracket19Routines
387 };
escLeftBracket19Routine(char32_t c)388 static char32_t escLeftBracket19Routine(char32_t c) {
389 c = read_unicode_character();
390 if (c == 0) return 0;
391 return doDispatch(c, escLeftBracket19Dispatch);
392 }
393
394 // Handle ESC [ 1 <more stuff> escape sequences
395 //
396 static CharacterDispatchRoutine escLeftBracket1Routines[] = {
397 homeKeyRoutine, escLeftBracket1SemicolonRoutine,
398 escLeftBracket15Routine,
399 escLeftBracket17Routine,
400 escLeftBracket18Routine,
401 escLeftBracket19Routine,
402 escFailureRoutine
403 };
404 static CharacterDispatch escLeftBracket1Dispatch = {
405 6, "~;5789", escLeftBracket1Routines
406 };
407
408 // Handle ESC [ 2 <more stuff> escape sequences
409 //
410
411 // (S)-F9
412 static CharacterDispatchRoutine escLeftBracket20Semicolon2Routines[] = {
413 f9KeyRoutine, escFailureRoutine
414 };
415 static CharacterDispatch escLeftBracket20Semicolon2Dispatch = {
416 1, "~", escLeftBracket20Semicolon2Routines
417 };
escLeftBracket20Semicolon2Routine(char32_t c)418 static char32_t escLeftBracket20Semicolon2Routine(char32_t c) {
419 c = read_unicode_character();
420 if (c == 0) return 0;
421 thisKeyMetaCtrl |= Replxx::KEY::BASE_SHIFT;
422 return doDispatch(c, escLeftBracket20Semicolon2Dispatch);
423 }
424
425 // (C)-F9
426 static CharacterDispatchRoutine escLeftBracket20Semicolon5Routines[] = {
427 f9KeyRoutine, escFailureRoutine
428 };
429 static CharacterDispatch escLeftBracket20Semicolon5Dispatch = {
430 1, "~", escLeftBracket20Semicolon5Routines
431 };
escLeftBracket20Semicolon5Routine(char32_t c)432 static char32_t escLeftBracket20Semicolon5Routine(char32_t c) {
433 c = read_unicode_character();
434 if (c == 0) return 0;
435 thisKeyMetaCtrl |= Replxx::KEY::BASE_CONTROL;
436 return doDispatch(c, escLeftBracket20Semicolon5Dispatch);
437 }
438
439 static CharacterDispatchRoutine escLeftBracket20SemicolonRoutines[] = {
440 escLeftBracket20Semicolon2Routine, escLeftBracket20Semicolon5Routine, escFailureRoutine
441 };
442 static CharacterDispatch escLeftBracket20SemicolonDispatch = {
443 2, "25", escLeftBracket20SemicolonRoutines
444 };
escLeftBracket20SemicolonRoutine(char32_t c)445 static char32_t escLeftBracket20SemicolonRoutine(char32_t c) {
446 c = read_unicode_character();
447 if (c == 0) return 0;
448 return doDispatch(c, escLeftBracket20SemicolonDispatch);
449 }
450
451 static CharacterDispatchRoutine escLeftBracket200Routines[] = {
452 bracketPasteStartKeyRoutine, escFailureRoutine
453 };
454 static CharacterDispatch escLeftBracket200Dispatch = {
455 1, "~", escLeftBracket200Routines
456 };
escLeftBracket200Routine(char32_t c)457 static char32_t escLeftBracket200Routine(char32_t c) {
458 c = read_unicode_character();
459 if (c == 0) return 0;
460 return doDispatch(c, escLeftBracket200Dispatch);
461 }
462
463 static CharacterDispatchRoutine escLeftBracket201Routines[] = {
464 bracketPasteFinishKeyRoutine, escFailureRoutine
465 };
466 static CharacterDispatch escLeftBracket201Dispatch = {
467 1, "~", escLeftBracket201Routines
468 };
escLeftBracket201Routine(char32_t c)469 static char32_t escLeftBracket201Routine(char32_t c) {
470 c = read_unicode_character();
471 if (c == 0) return 0;
472 return doDispatch(c, escLeftBracket201Dispatch);
473 }
474
475 static CharacterDispatchRoutine escLeftBracket20Routines[] = {
476 f9KeyRoutine, escLeftBracket20SemicolonRoutine, escLeftBracket200Routine, escLeftBracket201Routine, escFailureRoutine
477 };
478 static CharacterDispatch escLeftBracket20Dispatch = {
479 4, "~;01", escLeftBracket20Routines
480 };
escLeftBracket20Routine(char32_t c)481 static char32_t escLeftBracket20Routine(char32_t c) {
482 c = read_unicode_character();
483 if (c == 0) return 0;
484 return doDispatch(c, escLeftBracket20Dispatch);
485 }
486
487 // (S)-F10
488 static CharacterDispatchRoutine escLeftBracket21Semicolon2Routines[] = {
489 f10KeyRoutine, escFailureRoutine
490 };
491 static CharacterDispatch escLeftBracket21Semicolon2Dispatch = {
492 1, "~", escLeftBracket21Semicolon2Routines
493 };
escLeftBracket21Semicolon2Routine(char32_t c)494 static char32_t escLeftBracket21Semicolon2Routine(char32_t c) {
495 c = read_unicode_character();
496 if (c == 0) return 0;
497 thisKeyMetaCtrl |= Replxx::KEY::BASE_SHIFT;
498 return doDispatch(c, escLeftBracket21Semicolon2Dispatch);
499 }
500
501 // (C)-F10
502 static CharacterDispatchRoutine escLeftBracket21Semicolon5Routines[] = {
503 f10KeyRoutine, escFailureRoutine
504 };
505 static CharacterDispatch escLeftBracket21Semicolon5Dispatch = {
506 1, "~", escLeftBracket21Semicolon5Routines
507 };
escLeftBracket21Semicolon5Routine(char32_t c)508 static char32_t escLeftBracket21Semicolon5Routine(char32_t c) {
509 c = read_unicode_character();
510 if (c == 0) return 0;
511 thisKeyMetaCtrl |= Replxx::KEY::BASE_CONTROL;
512 return doDispatch(c, escLeftBracket21Semicolon5Dispatch);
513 }
514
515 static CharacterDispatchRoutine escLeftBracket21SemicolonRoutines[] = {
516 escLeftBracket21Semicolon2Routine, escLeftBracket21Semicolon5Routine, escFailureRoutine
517 };
518 static CharacterDispatch escLeftBracket21SemicolonDispatch = {
519 2, "25", escLeftBracket21SemicolonRoutines
520 };
escLeftBracket21SemicolonRoutine(char32_t c)521 static char32_t escLeftBracket21SemicolonRoutine(char32_t c) {
522 c = read_unicode_character();
523 if (c == 0) return 0;
524 return doDispatch(c, escLeftBracket21SemicolonDispatch);
525 }
526
527 static CharacterDispatchRoutine escLeftBracket21Routines[] = {
528 f10KeyRoutine, escLeftBracket21SemicolonRoutine, escFailureRoutine
529 };
530 static CharacterDispatch escLeftBracket21Dispatch = {
531 2, "~;", escLeftBracket21Routines
532 };
escLeftBracket21Routine(char32_t c)533 static char32_t escLeftBracket21Routine(char32_t c) {
534 c = read_unicode_character();
535 if (c == 0) return 0;
536 return doDispatch(c, escLeftBracket21Dispatch);
537 }
538
539 // (S)-F11
540 static CharacterDispatchRoutine escLeftBracket23Semicolon2Routines[] = {
541 f11KeyRoutine, escFailureRoutine
542 };
543 static CharacterDispatch escLeftBracket23Semicolon2Dispatch = {
544 1, "~", escLeftBracket23Semicolon2Routines
545 };
escLeftBracket23Semicolon2Routine(char32_t c)546 static char32_t escLeftBracket23Semicolon2Routine(char32_t c) {
547 c = read_unicode_character();
548 if (c == 0) return 0;
549 thisKeyMetaCtrl |= Replxx::KEY::BASE_SHIFT;
550 return doDispatch(c, escLeftBracket23Semicolon2Dispatch);
551 }
552
553 // (C)-F11
554 static CharacterDispatchRoutine escLeftBracket23Semicolon5Routines[] = {
555 f11KeyRoutine, escFailureRoutine
556 };
557 static CharacterDispatch escLeftBracket23Semicolon5Dispatch = {
558 1, "~", escLeftBracket23Semicolon5Routines
559 };
escLeftBracket23Semicolon5Routine(char32_t c)560 static char32_t escLeftBracket23Semicolon5Routine(char32_t c) {
561 c = read_unicode_character();
562 if (c == 0) return 0;
563 thisKeyMetaCtrl |= Replxx::KEY::BASE_CONTROL;
564 return doDispatch(c, escLeftBracket23Semicolon5Dispatch);
565 }
566
567 static CharacterDispatchRoutine escLeftBracket23SemicolonRoutines[] = {
568 escLeftBracket23Semicolon2Routine, escLeftBracket23Semicolon5Routine, escFailureRoutine
569 };
570 static CharacterDispatch escLeftBracket23SemicolonDispatch = {
571 2, "25", escLeftBracket23SemicolonRoutines
572 };
escLeftBracket23SemicolonRoutine(char32_t c)573 static char32_t escLeftBracket23SemicolonRoutine(char32_t c) {
574 c = read_unicode_character();
575 if (c == 0) return 0;
576 return doDispatch(c, escLeftBracket23SemicolonDispatch);
577 }
578
579 static CharacterDispatchRoutine escLeftBracket23Routines[] = {
580 f11KeyRoutine, escLeftBracket23SemicolonRoutine, escFailureRoutine
581 };
582 static CharacterDispatch escLeftBracket23Dispatch = {
583 2, "~;", escLeftBracket23Routines
584 };
escLeftBracket23Routine(char32_t c)585 static char32_t escLeftBracket23Routine(char32_t c) {
586 c = read_unicode_character();
587 if (c == 0) return 0;
588 return doDispatch(c, escLeftBracket23Dispatch);
589 }
590
591 // (S)-F12
592 static CharacterDispatchRoutine escLeftBracket24Semicolon2Routines[] = {
593 f12KeyRoutine, escFailureRoutine
594 };
595 static CharacterDispatch escLeftBracket24Semicolon2Dispatch = {
596 1, "~", escLeftBracket24Semicolon2Routines
597 };
escLeftBracket24Semicolon2Routine(char32_t c)598 static char32_t escLeftBracket24Semicolon2Routine(char32_t c) {
599 c = read_unicode_character();
600 if (c == 0) return 0;
601 thisKeyMetaCtrl |= Replxx::KEY::BASE_SHIFT;
602 return doDispatch(c, escLeftBracket24Semicolon2Dispatch);
603 }
604
605 // (C)-F12
606 static CharacterDispatchRoutine escLeftBracket24Semicolon5Routines[] = {
607 f12KeyRoutine, escFailureRoutine
608 };
609 static CharacterDispatch escLeftBracket24Semicolon5Dispatch = {
610 1, "~", escLeftBracket24Semicolon5Routines
611 };
escLeftBracket24Semicolon5Routine(char32_t c)612 static char32_t escLeftBracket24Semicolon5Routine(char32_t c) {
613 c = read_unicode_character();
614 if (c == 0) return 0;
615 thisKeyMetaCtrl |= Replxx::KEY::BASE_CONTROL;
616 return doDispatch(c, escLeftBracket24Semicolon5Dispatch);
617 }
618
619 static CharacterDispatchRoutine escLeftBracket24SemicolonRoutines[] = {
620 escLeftBracket24Semicolon2Routine, escLeftBracket24Semicolon5Routine, escFailureRoutine
621 };
622 static CharacterDispatch escLeftBracket24SemicolonDispatch = {
623 2, "25", escLeftBracket24SemicolonRoutines
624 };
escLeftBracket24SemicolonRoutine(char32_t c)625 static char32_t escLeftBracket24SemicolonRoutine(char32_t c) {
626 c = read_unicode_character();
627 if (c == 0) return 0;
628 return doDispatch(c, escLeftBracket24SemicolonDispatch);
629 }
630
631 static CharacterDispatchRoutine escLeftBracket24Routines[] = {
632 f12KeyRoutine, escLeftBracket24SemicolonRoutine, escFailureRoutine
633 };
634 static CharacterDispatch escLeftBracket24Dispatch = {
635 2, "~;", escLeftBracket24Routines
636 };
escLeftBracket24Routine(char32_t c)637 static char32_t escLeftBracket24Routine(char32_t c) {
638 c = read_unicode_character();
639 if (c == 0) return 0;
640 return doDispatch(c, escLeftBracket24Dispatch);
641 }
642
643 // Handle ESC [ 2 <more stuff> escape sequences
644 //
645 static CharacterDispatchRoutine escLeftBracket2Routines[] = {
646 insertKeyRoutine,
647 escLeftBracket20Routine,
648 escLeftBracket21Routine,
649 escLeftBracket23Routine,
650 escLeftBracket24Routine,
651 escFailureRoutine
652 };
653 static CharacterDispatch escLeftBracket2Dispatch = {
654 5, "~0134", escLeftBracket2Routines
655 };
656
657 // Handle ESC [ 3 <more stuff> escape sequences
658 //
659 static CharacterDispatchRoutine escLeftBracket3Routines[] = {
660 deleteKeyRoutine, escFailureRoutine
661 };
662
663 static CharacterDispatch escLeftBracket3Dispatch = {
664 1, "~", escLeftBracket3Routines
665 };
666
667 // Handle ESC [ 4 <more stuff> escape sequences
668 //
669 static CharacterDispatchRoutine escLeftBracket4Routines[] = {
670 endKeyRoutine, escFailureRoutine
671 };
672 static CharacterDispatch escLeftBracket4Dispatch = {
673 1, "~", escLeftBracket4Routines
674 };
675
676 // Handle ESC [ 5 <more stuff> escape sequences
677 //
678 static CharacterDispatchRoutine escLeftBracket5Semicolon5Routines[] = {
679 pageUpKeyRoutine, escFailureRoutine
680 };
681 static CharacterDispatch escLeftBracket5Semicolon5Dispatch = {
682 1, "~", escLeftBracket5Semicolon5Routines
683 };
escLeftBracket5Semicolon5Routine(char32_t c)684 static char32_t escLeftBracket5Semicolon5Routine(char32_t c) {
685 c = read_unicode_character();
686 if (c == 0) return 0;
687 thisKeyMetaCtrl |= Replxx::KEY::BASE_CONTROL;
688 return doDispatch(c, escLeftBracket5Semicolon5Dispatch);
689 }
690 static CharacterDispatchRoutine escLeftBracket5SemicolonRoutines[] = {
691 escLeftBracket5Semicolon5Routine,
692 escFailureRoutine
693 };
694 static CharacterDispatch escLeftBracket5SemicolonDispatch = {
695 1, "5", escLeftBracket5SemicolonRoutines
696 };
escLeftBracket5SemicolonRoutine(char32_t c)697 static char32_t escLeftBracket5SemicolonRoutine(char32_t c) {
698 c = read_unicode_character();
699 if (c == 0) return 0;
700 return doDispatch(c, escLeftBracket5SemicolonDispatch);
701 }
702
703 static CharacterDispatchRoutine escLeftBracket5Routines[] = {
704 pageUpKeyRoutine, escLeftBracket5SemicolonRoutine, escFailureRoutine
705 };
706 static CharacterDispatch escLeftBracket5Dispatch = {
707 2, "~;", escLeftBracket5Routines
708 };
709
710 // Handle ESC [ 6 <more stuff> escape sequences
711 //
712 static CharacterDispatchRoutine escLeftBracket6Semicolon5Routines[] = {
713 pageDownKeyRoutine, escFailureRoutine
714 };
715 static CharacterDispatch escLeftBracket6Semicolon5Dispatch = {
716 1, "~", escLeftBracket6Semicolon5Routines
717 };
escLeftBracket6Semicolon5Routine(char32_t c)718 static char32_t escLeftBracket6Semicolon5Routine(char32_t c) {
719 c = read_unicode_character();
720 if (c == 0) return 0;
721 thisKeyMetaCtrl |= Replxx::KEY::BASE_CONTROL;
722 return doDispatch(c, escLeftBracket6Semicolon5Dispatch);
723 }
724 static CharacterDispatchRoutine escLeftBracket6SemicolonRoutines[] = {
725 escLeftBracket6Semicolon5Routine,
726 escFailureRoutine
727 };
728 static CharacterDispatch escLeftBracket6SemicolonDispatch = {
729 1, "5", escLeftBracket6SemicolonRoutines
730 };
escLeftBracket6SemicolonRoutine(char32_t c)731 static char32_t escLeftBracket6SemicolonRoutine(char32_t c) {
732 c = read_unicode_character();
733 if (c == 0) return 0;
734 return doDispatch(c, escLeftBracket6SemicolonDispatch);
735 }
736
737 static CharacterDispatchRoutine escLeftBracket6Routines[] = {
738 pageDownKeyRoutine, escLeftBracket6SemicolonRoutine, escFailureRoutine
739 };
740 static CharacterDispatch escLeftBracket6Dispatch = {
741 2, "~;", escLeftBracket6Routines
742 };
743
744 // Handle ESC [ 7 <more stuff> escape sequences
745 //
746 static CharacterDispatchRoutine escLeftBracket7Routines[] = {
747 homeKeyRoutine, escFailureRoutine
748 };
749 static CharacterDispatch escLeftBracket7Dispatch = {
750 1, "~", escLeftBracket7Routines
751 };
752
753 // Handle ESC [ 8 <more stuff> escape sequences
754 //
755 static CharacterDispatchRoutine escLeftBracket8Routines[] = {
756 endKeyRoutine, escFailureRoutine
757 };
758 static CharacterDispatch escLeftBracket8Dispatch = {
759 1, "~", escLeftBracket8Routines
760 };
761
762 // Handle ESC [ <digit> escape sequences
763 //
escLeftBracket0Routine(char32_t c)764 static char32_t escLeftBracket0Routine(char32_t c) {
765 return escFailureRoutine(c);
766 }
escLeftBracket1Routine(char32_t c)767 static char32_t escLeftBracket1Routine(char32_t c) {
768 c = read_unicode_character();
769 if (c == 0) return 0;
770 return doDispatch(c, escLeftBracket1Dispatch);
771 }
escLeftBracket2Routine(char32_t c)772 static char32_t escLeftBracket2Routine(char32_t c) {
773 c = read_unicode_character();
774 if (c == 0) return 0;
775 return doDispatch(c, escLeftBracket2Dispatch);
776 }
escLeftBracket3Routine(char32_t c)777 static char32_t escLeftBracket3Routine(char32_t c) {
778 c = read_unicode_character();
779 if (c == 0) return 0;
780 return doDispatch(c, escLeftBracket3Dispatch);
781 }
escLeftBracket4Routine(char32_t c)782 static char32_t escLeftBracket4Routine(char32_t c) {
783 c = read_unicode_character();
784 if (c == 0) return 0;
785 return doDispatch(c, escLeftBracket4Dispatch);
786 }
escLeftBracket5Routine(char32_t c)787 static char32_t escLeftBracket5Routine(char32_t c) {
788 c = read_unicode_character();
789 if (c == 0) return 0;
790 return doDispatch(c, escLeftBracket5Dispatch);
791 }
escLeftBracket6Routine(char32_t c)792 static char32_t escLeftBracket6Routine(char32_t c) {
793 c = read_unicode_character();
794 if (c == 0) return 0;
795 return doDispatch(c, escLeftBracket6Dispatch);
796 }
escLeftBracket7Routine(char32_t c)797 static char32_t escLeftBracket7Routine(char32_t c) {
798 c = read_unicode_character();
799 if (c == 0) return 0;
800 return doDispatch(c, escLeftBracket7Dispatch);
801 }
escLeftBracket8Routine(char32_t c)802 static char32_t escLeftBracket8Routine(char32_t c) {
803 c = read_unicode_character();
804 if (c == 0) return 0;
805 return doDispatch(c, escLeftBracket8Dispatch);
806 }
escLeftBracket9Routine(char32_t c)807 static char32_t escLeftBracket9Routine(char32_t c) {
808 return escFailureRoutine(c);
809 }
810
811 // Handle ESC [ <more stuff> escape sequences
812 //
813 static CharacterDispatchRoutine escLeftBracketRoutines[] = {
814 upArrowKeyRoutine, downArrowKeyRoutine, rightArrowKeyRoutine,
815 leftArrowKeyRoutine, homeKeyRoutine, endKeyRoutine,
816 shiftTabRoutine,
817 escLeftBracket0Routine, escLeftBracket1Routine, escLeftBracket2Routine,
818 escLeftBracket3Routine, escLeftBracket4Routine, escLeftBracket5Routine,
819 escLeftBracket6Routine, escLeftBracket7Routine, escLeftBracket8Routine,
820 escLeftBracket9Routine, escFailureRoutine
821 };
822 static CharacterDispatch escLeftBracketDispatch = {17, "ABCDHFZ0123456789",
823 escLeftBracketRoutines};
824
825 // Handle ESC O <char> escape sequences
826 //
827 static CharacterDispatchRoutine escORoutines[] = {
828 upArrowKeyRoutine, downArrowKeyRoutine, rightArrowKeyRoutine,
829 leftArrowKeyRoutine, homeKeyRoutine, endKeyRoutine,
830 f1KeyRoutine, f2KeyRoutine, f3KeyRoutine,
831 f4KeyRoutine,
832 ctrlUpArrowKeyRoutine, ctrlDownArrowKeyRoutine, ctrlRightArrowKeyRoutine,
833 ctrlLeftArrowKeyRoutine, escFailureRoutine
834 };
835 static CharacterDispatch escODispatch = {14, "ABCDHFPQRSabcd", escORoutines};
836
837 // Initial ESC dispatch -- could be a Meta prefix or the start of an escape
838 // sequence
839 //
escLeftBracketRoutine(char32_t c)840 static char32_t escLeftBracketRoutine(char32_t c) {
841 c = read_unicode_character();
842 if (c == 0) return 0;
843 return doDispatch(c, escLeftBracketDispatch);
844 }
escORoutine(char32_t c)845 static char32_t escORoutine(char32_t c) {
846 c = read_unicode_character();
847 if (c == 0) return 0;
848 return doDispatch(c, escODispatch);
849 }
850 static char32_t setMetaRoutine(char32_t c); // need forward reference
851 static CharacterDispatchRoutine escRoutines[] = {
852 escLeftBracketRoutine, escORoutine, setMetaRoutine
853 };
854 static CharacterDispatch escDispatch = {2, "[O", escRoutines};
855
856 // Initial dispatch -- we are not in the middle of anything yet
857 //
escRoutine(char32_t c)858 static char32_t escRoutine(char32_t c) {
859 c = read_unicode_character();
860 if (c == 0) return 0;
861 return doDispatch(c, escDispatch);
862 }
863 static CharacterDispatchRoutine initialRoutines[] = {
864 escRoutine, deleteCharRoutine, normalKeyRoutine
865 };
866 static CharacterDispatch initialDispatch = {2, "\x1B\x7F", initialRoutines};
867
868 // Special handling for the ESC key because it does double duty
869 //
setMetaRoutine(char32_t c)870 static char32_t setMetaRoutine(char32_t c) {
871 thisKeyMetaCtrl = Replxx::KEY::BASE_META;
872 if (c == 0x1B) { // another ESC, stay in ESC processing mode
873 c = read_unicode_character();
874 if (c == 0) return 0;
875 return doDispatch(c, escDispatch);
876 }
877 return doDispatch(c, initialDispatch);
878 }
879
doDispatch(char32_t c)880 char32_t doDispatch(char32_t c) {
881 EscapeSequenceProcessing::thisKeyMetaCtrl = 0; // no modifiers yet at initialDispatch
882 return doDispatch(c, initialDispatch);
883 }
884
885 } // namespace EscapeSequenceProcessing // move these out of global namespace
886
887 }
888
889 #endif /* #ifndef _WIN32 */
890
891