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