teken.c revision 261551
1275970Scy/*-
2275970Scy * Copyright (c) 2008-2009 Ed Schouten <ed@FreeBSD.org>
3275970Scy * All rights reserved.
4275970Scy *
5275970Scy * Redistribution and use in source and binary forms, with or without
6275970Scy * modification, are permitted provided that the following conditions
7275970Scy * are met:
8275970Scy * 1. Redistributions of source code must retain the above copyright
9275970Scy *    notice, this list of conditions and the following disclaimer.
10275970Scy * 2. Redistributions in binary form must reproduce the above copyright
11275970Scy *    notice, this list of conditions and the following disclaimer in the
12275970Scy *    documentation and/or other materials provided with the distribution.
13275970Scy *
14275970Scy * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15275970Scy * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16275970Scy * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17275970Scy * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18275970Scy * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19275970Scy * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20275970Scy * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21275970Scy * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22275970Scy * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23275970Scy * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24275970Scy * SUCH DAMAGE.
25275970Scy *
26275970Scy * $FreeBSD: head/sys/teken/teken.c 261551 2014-02-06 13:28:06Z ray $
27275970Scy */
28275970Scy
29275970Scy#include <sys/cdefs.h>
30275970Scy#if defined(__FreeBSD__) && defined(_KERNEL)
31275970Scy#include <sys/param.h>
32275970Scy#include <sys/lock.h>
33275970Scy#include <sys/systm.h>
34275970Scy#define	teken_assert(x)		MPASS(x)
35275970Scy#else /* !(__FreeBSD__ && _KERNEL) */
36275970Scy#include <sys/types.h>
37275970Scy#include <assert.h>
38275970Scy#include <stdint.h>
39275970Scy#include <stdio.h>
40275970Scy#include <string.h>
41275970Scy#define	teken_assert(x)		assert(x)
42275970Scy#endif /* __FreeBSD__ && _KERNEL */
43275970Scy
44275970Scy/* debug messages */
45275970Scy#define	teken_printf(x,...)
46275970Scy
47275970Scy/* Private flags for t_stateflags. */
48275970Scy#define	TS_FIRSTDIGIT	0x0001	/* First numeric digit in escape sequence. */
49275970Scy#define	TS_INSERT	0x0002	/* Insert mode. */
50275970Scy#define	TS_AUTOWRAP	0x0004	/* Autowrap. */
51275970Scy#define	TS_ORIGIN	0x0008	/* Origin mode. */
52275970Scy#define	TS_WRAPPED	0x0010	/* Next character should be printed on col 0. */
53275970Scy#define	TS_8BIT		0x0020	/* UTF-8 disabled. */
54275970Scy#define	TS_CONS25	0x0040	/* cons25 emulation. */
55275970Scy#define	TS_INSTRING	0x0080	/* Inside string. */
56275970Scy#define	TS_CURSORKEYS	0x0100	/* Cursor keys mode. */
57275970Scy
58275970Scy/* Character that blanks a cell. */
59275970Scy#define	BLANK	' '
60275970Scy
61275970Scy#include "teken.h"
62275970Scy#include "teken_wcwidth.h"
63275970Scy#include "teken_scs.h"
64275970Scy
65275970Scystatic teken_state_t	teken_state_init;
66275970Scy
67275970Scy/*
68275970Scy * Wrappers for hooks.
69275970Scy */
70275970Scy
71275970Scystatic inline void
72275970Scyteken_funcs_bell(teken_t *t)
73275970Scy{
74275970Scy
75275970Scy	t->t_funcs->tf_bell(t->t_softc);
76275970Scy}
77275970Scy
78275970Scystatic inline void
79275970Scyteken_funcs_cursor(teken_t *t)
80275970Scy{
81275970Scy
82275970Scy	teken_assert(t->t_cursor.tp_row < t->t_winsize.tp_row);
83275970Scy	teken_assert(t->t_cursor.tp_col < t->t_winsize.tp_col);
84275970Scy
85275970Scy	t->t_funcs->tf_cursor(t->t_softc, &t->t_cursor);
86275970Scy}
87275970Scy
88275970Scystatic inline void
89275970Scyteken_funcs_putchar(teken_t *t, const teken_pos_t *p, teken_char_t c,
90275970Scy    const teken_attr_t *a)
91275970Scy{
92275970Scy
93275970Scy	teken_assert(p->tp_row < t->t_winsize.tp_row);
94275970Scy	teken_assert(p->tp_col < t->t_winsize.tp_col);
95275970Scy
96275970Scy	t->t_funcs->tf_putchar(t->t_softc, p, c, a);
97275970Scy}
98275970Scy
99275970Scystatic inline void
100275970Scyteken_funcs_fill(teken_t *t, const teken_rect_t *r,
101275970Scy    const teken_char_t c, const teken_attr_t *a)
102275970Scy{
103275970Scy
104275970Scy	teken_assert(r->tr_end.tp_row > r->tr_begin.tp_row);
105275970Scy	teken_assert(r->tr_end.tp_row <= t->t_winsize.tp_row);
106275970Scy	teken_assert(r->tr_end.tp_col > r->tr_begin.tp_col);
107275970Scy	teken_assert(r->tr_end.tp_col <= t->t_winsize.tp_col);
108275970Scy
109275970Scy	t->t_funcs->tf_fill(t->t_softc, r, c, a);
110275970Scy}
111275970Scy
112275970Scystatic inline void
113275970Scyteken_funcs_copy(teken_t *t, const teken_rect_t *r, const teken_pos_t *p)
114275970Scy{
115275970Scy
116275970Scy	teken_assert(r->tr_end.tp_row > r->tr_begin.tp_row);
117275970Scy	teken_assert(r->tr_end.tp_row <= t->t_winsize.tp_row);
118275970Scy	teken_assert(r->tr_end.tp_col > r->tr_begin.tp_col);
119275970Scy	teken_assert(r->tr_end.tp_col <= t->t_winsize.tp_col);
120275970Scy	teken_assert(p->tp_row + (r->tr_end.tp_row - r->tr_begin.tp_row) <= t->t_winsize.tp_row);
121275970Scy	teken_assert(p->tp_col + (r->tr_end.tp_col - r->tr_begin.tp_col) <= t->t_winsize.tp_col);
122275970Scy
123275970Scy	t->t_funcs->tf_copy(t->t_softc, r, p);
124275970Scy}
125275970Scy
126275970Scystatic inline void
127275970Scyteken_funcs_param(teken_t *t, int cmd, unsigned int value)
128275970Scy{
129275970Scy
130275970Scy	t->t_funcs->tf_param(t->t_softc, cmd, value);
131275970Scy}
132275970Scy
133275970Scystatic inline void
134275970Scyteken_funcs_respond(teken_t *t, const void *buf, size_t len)
135275970Scy{
136275970Scy
137275970Scy	t->t_funcs->tf_respond(t->t_softc, buf, len);
138275970Scy}
139275970Scy
140275970Scy#include "teken_subr.h"
141275970Scy#include "teken_subr_compat.h"
142275970Scy
143275970Scy/*
144275970Scy * Programming interface.
145275970Scy */
146275970Scy
147275970Scyvoid
148275970Scyteken_init(teken_t *t, const teken_funcs_t *tf, void *softc)
149275970Scy{
150275970Scy	teken_pos_t tp = { .tp_row = 24, .tp_col = 80 };
151275970Scy
152275970Scy	t->t_funcs = tf;
153275970Scy	t->t_softc = softc;
154275970Scy
155275970Scy	t->t_nextstate = teken_state_init;
156275970Scy	t->t_stateflags = 0;
157275970Scy	t->t_utf8_left = 0;
158275970Scy
159275970Scy	t->t_defattr.ta_format = 0;
160275970Scy	t->t_defattr.ta_fgcolor = TC_WHITE;
161275970Scy	t->t_defattr.ta_bgcolor = TC_BLACK;
162275970Scy	teken_subr_do_reset(t);
163275970Scy
164275970Scy	teken_set_winsize(t, &tp);
165275970Scy}
166275970Scy
167275970Scystatic void
168275970Scyteken_input_char(teken_t *t, teken_char_t c)
169275970Scy{
170275970Scy
171275970Scy	/*
172275970Scy	 * There is no support for DCS and OSC.  Just discard strings
173275970Scy	 * until we receive characters that may indicate string
174275970Scy	 * termination.
175275970Scy	 */
176275970Scy	if (t->t_stateflags & TS_INSTRING) {
177275970Scy		switch (c) {
178275970Scy		case '\x1B':
179275970Scy			t->t_stateflags &= ~TS_INSTRING;
180275970Scy			break;
181275970Scy		case '\a':
182275970Scy			t->t_stateflags &= ~TS_INSTRING;
183275970Scy			return;
184275970Scy		default:
185275970Scy			return;
186275970Scy		}
187275970Scy	}
188275970Scy
189275970Scy	switch (c) {
190275970Scy	case '\0':
191275970Scy		break;
192275970Scy	case '\a':
193275970Scy		teken_subr_bell(t);
194275970Scy		break;
195275970Scy	case '\b':
196275970Scy		teken_subr_backspace(t);
197275970Scy		break;
198275970Scy	case '\n':
199275970Scy	case '\x0B':
200275970Scy		teken_subr_newline(t);
201275970Scy		break;
202275970Scy	case '\x0C':
203275970Scy		teken_subr_newpage(t);
204275970Scy		break;
205275970Scy	case '\x0E':
206275970Scy		if (t->t_stateflags & TS_CONS25)
207275970Scy			t->t_nextstate(t, c);
208275970Scy		else
209275970Scy			t->t_curscs = 1;
210275970Scy		break;
211275970Scy	case '\x0F':
212275970Scy		if (t->t_stateflags & TS_CONS25)
213275970Scy			t->t_nextstate(t, c);
214275970Scy		else
215275970Scy			t->t_curscs = 0;
216275970Scy		break;
217275970Scy	case '\r':
218275970Scy		teken_subr_carriage_return(t);
219275970Scy		break;
220275970Scy	case '\t':
221275970Scy		teken_subr_horizontal_tab(t);
222275970Scy		break;
223275970Scy	default:
224275970Scy		t->t_nextstate(t, c);
225275970Scy		break;
226275970Scy	}
227275970Scy
228275970Scy	/* Post-processing assertions. */
229275970Scy	teken_assert(t->t_cursor.tp_row >= t->t_originreg.ts_begin);
230275970Scy	teken_assert(t->t_cursor.tp_row < t->t_originreg.ts_end);
231275970Scy	teken_assert(t->t_cursor.tp_row < t->t_winsize.tp_row);
232275970Scy	teken_assert(t->t_cursor.tp_col < t->t_winsize.tp_col);
233275970Scy	teken_assert(t->t_saved_cursor.tp_row < t->t_winsize.tp_row);
234275970Scy	teken_assert(t->t_saved_cursor.tp_col < t->t_winsize.tp_col);
235275970Scy	teken_assert(t->t_scrollreg.ts_end <= t->t_winsize.tp_row);
236275970Scy	teken_assert(t->t_scrollreg.ts_begin < t->t_scrollreg.ts_end);
237275970Scy	/* Origin region has to be window size or the same as scrollreg. */
238275970Scy	teken_assert((t->t_originreg.ts_begin == t->t_scrollreg.ts_begin &&
239275970Scy	    t->t_originreg.ts_end == t->t_scrollreg.ts_end) ||
240275970Scy	    (t->t_originreg.ts_begin == 0 &&
241275970Scy	    t->t_originreg.ts_end == t->t_winsize.tp_row));
242275970Scy}
243275970Scy
244275970Scystatic void
245275970Scyteken_input_byte(teken_t *t, unsigned char c)
246275970Scy{
247275970Scy
248275970Scy	/*
249275970Scy	 * UTF-8 handling.
250275970Scy	 */
251275970Scy	if ((c & 0x80) == 0x00 || t->t_stateflags & TS_8BIT) {
252275970Scy		/* One-byte sequence. */
253275970Scy		t->t_utf8_left = 0;
254275970Scy		teken_input_char(t, c);
255275970Scy	} else if ((c & 0xe0) == 0xc0) {
256275970Scy		/* Two-byte sequence. */
257275970Scy		t->t_utf8_left = 1;
258275970Scy		t->t_utf8_partial = c & 0x1f;
259275970Scy	} else if ((c & 0xf0) == 0xe0) {
260275970Scy		/* Three-byte sequence. */
261275970Scy		t->t_utf8_left = 2;
262275970Scy		t->t_utf8_partial = c & 0x0f;
263275970Scy	} else if ((c & 0xf8) == 0xf0) {
264275970Scy		/* Four-byte sequence. */
265275970Scy		t->t_utf8_left = 3;
266275970Scy		t->t_utf8_partial = c & 0x07;
267275970Scy	} else if ((c & 0xc0) == 0x80) {
268275970Scy		if (t->t_utf8_left == 0)
269275970Scy			return;
270275970Scy		t->t_utf8_left--;
271275970Scy		t->t_utf8_partial = (t->t_utf8_partial << 6) | (c & 0x3f);
272275970Scy		if (t->t_utf8_left == 0) {
273275970Scy			teken_printf("Got UTF-8 char %x\n", t->t_utf8_partial);
274275970Scy			teken_input_char(t, t->t_utf8_partial);
275275970Scy		}
276275970Scy	}
277275970Scy}
278275970Scy
279275970Scyvoid
280275970Scyteken_input(teken_t *t, const void *buf, size_t len)
281275970Scy{
282275970Scy	const char *c = buf;
283275970Scy
284275970Scy	while (len-- > 0)
285275970Scy		teken_input_byte(t, *c++);
286275970Scy}
287275970Scy
288275970Scyconst teken_pos_t *
289275970Scyteken_get_cursor(teken_t *t)
290275970Scy{
291275970Scy
292275970Scy	return (&t->t_cursor);
293275970Scy}
294275970Scy
295275970Scyvoid
296275970Scyteken_set_cursor(teken_t *t, const teken_pos_t *p)
297275970Scy{
298275970Scy
299275970Scy	/* XXX: bounds checking with originreg! */
300275970Scy	teken_assert(p->tp_row < t->t_winsize.tp_row);
301275970Scy	teken_assert(p->tp_col < t->t_winsize.tp_col);
302275970Scy
303275970Scy	t->t_cursor = *p;
304275970Scy}
305275970Scy
306275970Scyconst teken_attr_t *
307275970Scyteken_get_curattr(teken_t *t)
308275970Scy{
309275970Scy
310275970Scy	return (&t->t_curattr);
311275970Scy}
312275970Scy
313275970Scyvoid
314275970Scyteken_set_curattr(teken_t *t, const teken_attr_t *a)
315275970Scy{
316275970Scy
317275970Scy	t->t_curattr = *a;
318275970Scy}
319275970Scy
320275970Scyconst teken_attr_t *
321275970Scyteken_get_defattr(teken_t *t)
322275970Scy{
323275970Scy
324275970Scy	return (&t->t_defattr);
325275970Scy}
326275970Scy
327275970Scyvoid
328275970Scyteken_set_defattr(teken_t *t, const teken_attr_t *a)
329275970Scy{
330275970Scy
331275970Scy	t->t_curattr = t->t_saved_curattr = t->t_defattr = *a;
332275970Scy}
333275970Scy
334275970Scyconst teken_pos_t *
335275970Scyteken_get_winsize(teken_t *t)
336275970Scy{
337275970Scy
338275970Scy	return (&t->t_winsize);
339275970Scy}
340275970Scy
341275970Scystatic void
342275970Scyteken_trim_cursor_pos(teken_t *t, const teken_pos_t *new)
343275970Scy{
344275970Scy	const teken_pos_t *cur;
345275970Scy
346275970Scy	cur = &t->t_winsize;
347275970Scy
348275970Scy	if (cur->tp_row < new->tp_row || cur->tp_col < new->tp_col)
349275970Scy		return;
350275970Scy	if (t->t_cursor.tp_row >= new->tp_row)
351275970Scy		t->t_cursor.tp_row = new->tp_row - 1;
352275970Scy	if (t->t_cursor.tp_col >= new->tp_col)
353275970Scy		t->t_cursor.tp_col = new->tp_col - 1;
354275970Scy}
355275970Scy
356275970Scyvoid
357275970Scyteken_set_winsize(teken_t *t, const teken_pos_t *p)
358275970Scy{
359275970Scy
360275970Scy	teken_trim_cursor_pos(t, p);
361275970Scy	t->t_winsize = *p;
362275970Scy	teken_subr_do_reset(t);
363275970Scy}
364275970Scy
365275970Scyvoid
366275970Scyteken_set_winsize_noreset(teken_t *t, const teken_pos_t *p)
367275970Scy{
368275970Scy
369275970Scy	teken_trim_cursor_pos(t, p);
370275970Scy	t->t_winsize = *p;
371275970Scy	teken_subr_do_resize(t);
372275970Scy}
373275970Scy
374275970Scyvoid
375275970Scyteken_set_8bit(teken_t *t)
376275970Scy{
377275970Scy
378275970Scy	t->t_stateflags |= TS_8BIT;
379275970Scy}
380275970Scy
381275970Scyvoid
382275970Scyteken_set_cons25(teken_t *t)
383275970Scy{
384275970Scy
385275970Scy	t->t_stateflags |= TS_CONS25;
386275970Scy}
387275970Scy
388275970Scy/*
389275970Scy * State machine.
390275970Scy */
391275970Scy
392275970Scystatic void
393275970Scyteken_state_switch(teken_t *t, teken_state_t *s)
394275970Scy{
395275970Scy
396275970Scy	t->t_nextstate = s;
397275970Scy	t->t_curnum = 0;
398275970Scy	t->t_stateflags |= TS_FIRSTDIGIT;
399275970Scy}
400275970Scy
401275970Scystatic int
402275970Scyteken_state_numbers(teken_t *t, teken_char_t c)
403275970Scy{
404275970Scy
405275970Scy	teken_assert(t->t_curnum < T_NUMSIZE);
406275970Scy
407275970Scy	if (c >= '0' && c <= '9') {
408275970Scy		/*
409275970Scy		 * Don't do math with the default value of 1 when a
410275970Scy		 * custom number is inserted.
411275970Scy		 */
412275970Scy		if (t->t_stateflags & TS_FIRSTDIGIT) {
413275970Scy			t->t_stateflags &= ~TS_FIRSTDIGIT;
414275970Scy			t->t_nums[t->t_curnum] = 0;
415275970Scy		} else {
416275970Scy			t->t_nums[t->t_curnum] *= 10;
417275970Scy		}
418275970Scy
419275970Scy		t->t_nums[t->t_curnum] += c - '0';
420275970Scy		return (1);
421275970Scy	} else if (c == ';') {
422275970Scy		if (t->t_stateflags & TS_FIRSTDIGIT)
423275970Scy			t->t_nums[t->t_curnum] = 0;
424275970Scy
425275970Scy		/* Only allow a limited set of arguments. */
426275970Scy		if (++t->t_curnum == T_NUMSIZE) {
427275970Scy			teken_state_switch(t, teken_state_init);
428275970Scy			return (1);
429275970Scy		}
430275970Scy
431275970Scy		t->t_stateflags |= TS_FIRSTDIGIT;
432275970Scy		return (1);
433275970Scy	} else {
434275970Scy		if (t->t_stateflags & TS_FIRSTDIGIT && t->t_curnum > 0) {
435275970Scy			/* Finish off the last empty argument. */
436275970Scy			t->t_nums[t->t_curnum] = 0;
437275970Scy			t->t_curnum++;
438275970Scy		} else if ((t->t_stateflags & TS_FIRSTDIGIT) == 0) {
439275970Scy			/* Also count the last argument. */
440275970Scy			t->t_curnum++;
441275970Scy		}
442275970Scy	}
443275970Scy
444275970Scy	return (0);
445275970Scy}
446275970Scy
447275970Scyteken_color_t
448275970Scyteken_256to8(teken_color_t c)
449275970Scy{
450275970Scy	unsigned int r, g, b;
451275970Scy
452275970Scy	if (c < 16) {
453275970Scy		/* Traditional color indices. */
454275970Scy		return (c % 8);
455275970Scy	} else if (c >= 244) {
456275970Scy		/* Upper grayscale colors. */
457275970Scy		return (TC_WHITE);
458275970Scy	} else if (c >= 232) {
459275970Scy		/* Lower grayscale colors. */
460275970Scy		return (TC_BLACK);
461275970Scy	}
462275970Scy
463275970Scy	/* Convert to RGB. */
464275970Scy	c -= 16;
465275970Scy	b = c % 6;
466275970Scy	g = (c / 6) % 6;
467275970Scy	r = c / 36;
468275970Scy
469275970Scy	if (r < g) {
470275970Scy		/* Possibly green. */
471275970Scy		if (g < b)
472275970Scy			return (TC_BLUE);
473275970Scy		else if (g > b)
474275970Scy			return (TC_GREEN);
475275970Scy		else
476275970Scy			return (TC_CYAN);
477275970Scy	} else if (r > g) {
478275970Scy		/* Possibly red. */
479275970Scy		if (r < b)
480275970Scy			return (TC_BLUE);
481275970Scy		else if (r > b)
482275970Scy			return (TC_RED);
483275970Scy		else
484275970Scy			return (TC_MAGENTA);
485275970Scy	} else {
486275970Scy		/* Possibly brown. */
487275970Scy		if (g < b)
488275970Scy			return (TC_BLUE);
489275970Scy		else if (g > b)
490275970Scy			return (TC_BROWN);
491275970Scy		else if (r < 3)
492275970Scy			return (TC_BLACK);
493275970Scy		else
494275970Scy			return (TC_WHITE);
495275970Scy	}
496275970Scy}
497275970Scy
498275970Scystatic const char * const special_strings_cons25[] = {
499275970Scy	[TKEY_UP] = "\x1B[A",		[TKEY_DOWN] = "\x1B[B",
500275970Scy	[TKEY_LEFT] = "\x1B[D",		[TKEY_RIGHT] = "\x1B[C",
501275970Scy
502275970Scy	[TKEY_HOME] = "\x1B[H",		[TKEY_END] = "\x1B[F",
503275970Scy	[TKEY_INSERT] = "\x1B[L",	[TKEY_DELETE] = "\x7F",
504275970Scy	[TKEY_PAGE_UP] = "\x1B[I",	[TKEY_PAGE_DOWN] = "\x1B[G",
505275970Scy
506275970Scy	[TKEY_F1] = "\x1B[M",		[TKEY_F2] = "\x1B[N",
507275970Scy	[TKEY_F3] = "\x1B[O",		[TKEY_F4] = "\x1B[P",
508275970Scy	[TKEY_F5] = "\x1B[Q",		[TKEY_F6] = "\x1B[R",
509275970Scy	[TKEY_F7] = "\x1B[S",		[TKEY_F8] = "\x1B[T",
510275970Scy	[TKEY_F9] = "\x1B[U",		[TKEY_F10] = "\x1B[V",
511275970Scy	[TKEY_F11] = "\x1B[W",		[TKEY_F12] = "\x1B[X",
512275970Scy};
513275970Scy
514275970Scystatic const char * const special_strings_ckeys[] = {
515275970Scy	[TKEY_UP] = "\x1BOA",		[TKEY_DOWN] = "\x1BOB",
516275970Scy	[TKEY_LEFT] = "\x1BOD",		[TKEY_RIGHT] = "\x1BOC",
517275970Scy
518275970Scy	[TKEY_HOME] = "\x1BOH",		[TKEY_END] = "\x1BOF",
519275970Scy};
520275970Scy
521275970Scystatic const char * const special_strings_normal[] = {
522275970Scy	[TKEY_UP] = "\x1B[A",		[TKEY_DOWN] = "\x1B[B",
523275970Scy	[TKEY_LEFT] = "\x1B[D",		[TKEY_RIGHT] = "\x1B[C",
524275970Scy
525275970Scy	[TKEY_HOME] = "\x1B[H",		[TKEY_END] = "\x1B[F",
526275970Scy	[TKEY_INSERT] = "\x1B[2~",	[TKEY_DELETE] = "\x1B[3~",
527275970Scy	[TKEY_PAGE_UP] = "\x1B[5~",	[TKEY_PAGE_DOWN] = "\x1B[6~",
528275970Scy
529275970Scy	[TKEY_F1] = "\x1BOP",		[TKEY_F2] = "\x1BOQ",
530275970Scy	[TKEY_F3] = "\x1BOR",		[TKEY_F4] = "\x1BOS",
531275970Scy	[TKEY_F5] = "\x1B[15~",		[TKEY_F6] = "\x1B[17~",
532275970Scy	[TKEY_F7] = "\x1B[18~",		[TKEY_F8] = "\x1B[19~",
533275970Scy	[TKEY_F9] = "\x1B[20~",		[TKEY_F10] = "\x1B[21~",
534275970Scy	[TKEY_F11] = "\x1B[23~",	[TKEY_F12] = "\x1B[24~",
535275970Scy};
536275970Scy
537275970Scyconst char *
538275970Scyteken_get_sequence(teken_t *t, unsigned int k)
539275970Scy{
540275970Scy
541275970Scy	/* Cons25 mode. */
542275970Scy	if (t->t_stateflags & TS_CONS25 &&
543275970Scy	    k < sizeof special_strings_cons25 / sizeof(char *))
544275970Scy		return (special_strings_cons25[k]);
545275970Scy
546275970Scy	/* Cursor keys mode. */
547275970Scy	if (t->t_stateflags & TS_CURSORKEYS &&
548275970Scy	    k < sizeof special_strings_ckeys / sizeof(char *))
549275970Scy		return (special_strings_ckeys[k]);
550275970Scy
551275970Scy	/* Default xterm sequences. */
552275970Scy	if (k < sizeof special_strings_normal / sizeof(char *))
553275970Scy		return (special_strings_normal[k]);
554275970Scy
555275970Scy	return (NULL);
556275970Scy}
557275970Scy
558275970Scy#include "teken_state.h"
559275970Scy