Annotation of brogue-ce/src/platform/term.c, Revision 1.1.1.1
1.1 rubenllo 1: #include <ncurses.h>
2: #include "term.h"
3: #include <math.h>
4: #include <stdlib.h>
5: #include <string.h>
6:
7:
8: // As a rule, everything in term.c is the result of gradual evolutionary
9: // change. It's messy.
10:
11: #define COLORING(fg,bg) (((fg) & 0x0f) | (((bg) & 0x07) << 4))
12: #define COLOR_FG(color,fg) (((fg) & 0x0f) + ((color) & 0x70))
13: #define COLOR_BG(color,bg) (((color) & 0x0f) + (((bg) & 0x07) << 4))
14: #define COLOR_INDEX(color) (1 + ((color)&0x07) + (((color) >> 1) & 0x38))
15: #define COLOR_ATTR(color) (COLOR_PAIR(COLOR_INDEX(color)) | (((color)&0x08) ? A_BOLD : 0))
16:
17:
18: static struct { int curses, color; } videomode = { 0, 0 };
19:
20: static struct { int width, height; } minsize = { 80, 24 };
21:
22: static void init_coersion();
23:
24:
25: // 256 color mode stuff
26: static void initialize_prs();
27:
28: typedef struct {
29: int r, g, b, idx;
30: } intcolor;
31:
32: struct {
33: intcolor fore, back;
34: int count, next;
35: } prs[256];
36:
37:
38: typedef struct {
39: int ch, pair, shuffle;
40: intcolor fore, back;
41: } pairmode_cell;
42:
43: pairmode_cell *cell_buffer;
44:
45: enum {
46: coerce_16,
47: coerce_256
48: } colormode;
49:
50: int is_xterm;
51:
52:
53: //
54:
55: static void preparecolor ( ) {
56: // sixteen color mode colors (we use these in 256-color mode, too)
57: static int pairParts[8] = {
58: COLOR_BLACK, COLOR_RED, COLOR_GREEN, COLOR_YELLOW,
59: COLOR_BLUE, COLOR_MAGENTA, COLOR_CYAN, COLOR_WHITE
60: };
61:
62: int fg, bg;
63: for (bg=0; bg<8; bg++) {
64: for (fg=0; fg<8; fg++) {
65: init_pair(
66: COLOR_INDEX(COLORING(fg, bg)),
67: pairParts[fg], pairParts[bg]
68: );
69: }
70: }
71:
72: if (COLORS >= 256) {
73: colormode = coerce_256;
74: }
75: }
76:
77: static void term_title(const char *title) {
78: if (is_xterm) {
79: printf ("\033]2;%s\007", title); // ESC ]0; title BEL
80: }
81: }
82:
83: static void term_title_pop() {
84: if (is_xterm) {
85: term_title("Terminal");
86: printf ("\033[22;2t");
87: }
88: }
89: static void term_title_push() {
90: if (is_xterm) {
91: printf ("\033[23;2t");
92: }
93: }
94:
95: static void term_set_size(int h, int w) {
96: // works in gnome-terminal, but not xterm; causes trouble for maximized windows
97: if (is_xterm) {
98: // first, try resizing the height, in case only that is supported
99: printf ("\033[%dt", (h > 24 ? h : 24));
100:
101: // then try resizing both, in case we can
102: printf ("\033[8;%d;%dt", h, w);
103:
104: // then refresh so ncurses knows about it
105: refresh( );
106: }
107: }
108:
109: static void term_show_scrollbar(int show) {
110: // works in xterm, but not gnome-terminal
111: if (is_xterm) {
112: if (show) {
113: printf ("\033[?30h");
114: } else {
115: printf ("\033[?30l");
116: }
117: }
118: }
119:
120: static int curses_init( ) {
121: if (videomode.curses) return 0;
122:
123: // isterm?
124: initscr( );
125: if (!has_colors( )) {
126: endwin( );
127: fprintf (stderr, "Your terminal has no color support.\n");
128: return 1;
129: }
130:
131: start_color( );
132: clear( );
133: curs_set( 0 );
134: refresh( );
135: leaveok(stdscr, TRUE);
136: preparecolor( );
137: cbreak( );
138: noecho( );
139:
140: nodelay(stdscr, TRUE);
141: meta(stdscr, TRUE);
142: keypad(stdscr, TRUE);
143:
144: mousemask(BUTTON1_PRESSED | BUTTON1_RELEASED | REPORT_MOUSE_POSITION | BUTTON_SHIFT | BUTTON_CTRL, NULL);
145: mouseinterval(0); //do no click processing, thank you
146:
147: videomode.curses = 1;
148:
149: getmaxyx(stdscr, Term.height, Term.width);
150:
151: return 1;
152: }
153:
154:
155: static int term_start() {
156: char *term = getenv("TERM");
157: is_xterm = (strncmp(term, "xterm", 5) == 0) || (strncmp(term, "gnome", 5) == 0) || (strncmp(term, "st", 2) == 0);
158:
159: term_title_push();
160: term_show_scrollbar(0);
161:
162: int ok = curses_init();
163: init_coersion();
164:
165: return ok;
166: }
167:
168: static void term_end() {
169: term_title_pop();
170: clear();
171: refresh();
172: endwin();
173: }
174:
175: typedef struct CIE {
176: float X, Y, Z;
177: float x, y, z;
178: } CIE;
179:
180: typedef struct Lab {
181: float L, a, b;
182: } Lab;
183:
184: #define DARK 0.0
185: #define DIM 0.1
186: #define MID 0.3
187: #define HALFBRIGHT 0.5
188: #define BRIGHT 0.9
189:
190: fcolor palette[16] = {
191: {DARK, DARK, DARK},
192: {MID, DARK, DARK},
193: {DARK, MID, DARK},
194: {MID, .8 * MID, DIM},
195: {DARK, DARK, MID},
196: {MID + DIM, DARK, MID},
197: {DARK, MID, MID},
198: {HALFBRIGHT, HALFBRIGHT, HALFBRIGHT},
199:
200: {MID, MID, MID},
201: {BRIGHT, DARK, DARK},
202: {DARK, BRIGHT, DARK},
203: {BRIGHT, BRIGHT, DARK},
204: {HALFBRIGHT, MID, BRIGHT},
205: {BRIGHT, HALFBRIGHT, BRIGHT},
206: {DARK, BRIGHT, BRIGHT},
207: {BRIGHT, BRIGHT, BRIGHT}
208: };
209:
210: CIE ciePalette[16];
211: Lab labPalette[16];
212: CIE adamsPalette[16];
213:
214: static CIE white;
215:
216: static CIE toCIE(fcolor c) {
217: double a = 0.055;
218:
219: // http://en.wikipedia.org/wiki/SRGB_color_space#The_reverse_transformation
220:
221: c.r = c.r <= 0.04045 ? c.r / 12.92 : pow((c.r + a) / (1 + a), 2.4);
222: c.g = c.g <= 0.04045 ? c.g / 12.92 : pow((c.g + a) / (1 + a), 2.4);
223: c.b = c.b <= 0.04045 ? c.b / 12.92 : pow((c.b + a) / (1 + a), 2.4);
224:
225: CIE cie;
226: cie.X = 0.4124 * c.r + 0.3576 * c.g + 0.1805 * c.b;
227: cie.Y = 0.2126 * c.r + 0.7152 * c.g + 0.0722 * c.b;
228: cie.Z = 0.0193 * c.r + 0.1192 * c.g + 0.9505 * c.b;
229:
230: float sum = cie.X + cie.Y + cie.Z;
231: if (sum == 0.0) sum = 1.0;
232: cie.x = cie.X / sum;
233: cie.y = cie.Y / sum;
234: cie.z = 1.0 - cie.x - cie.y;
235:
236: return cie;
237: }
238:
239: static float Labf(float t) {
240: return t > ((6.0/29.0) * (6.0/29.0) * (6.0/29.0)) ? pow(t, 1.0/3.0) : ((1.0/3.0) * (29.0 / 6.0) * (29.0 / 6.0)) * t + (4.0 / 29.0);
241: }
242:
243: static Lab toLab(CIE *c) {
244: CIE n = (CIE) {Labf(c->X / white.X), Labf(c->Y / white.Y), Labf(c->Z / white.Z)};
245: Lab l;
246:
247: // http://en.wikipedia.org/wiki/L*a*b*#RGB_and_CMYK_conversions
248: l.L = 116.0 * n.Y - 16;
249: l.a = 500.0 * (n.X - n.Y);
250: l.b = 200.0 * (n.Y - n.Z);
251:
252: return l;
253: }
254:
255: static float munsellSloanGodlove(float t) {
256: return sqrt(1.4742 * t - 0.004743 * t * t);
257: }
258:
259: static CIE adams(CIE *v) {
260: CIE c;
261: c.Y = munsellSloanGodlove(v->Y);
262: c.X = munsellSloanGodlove((white.Y / white.X) * v->X) - c.Y;
263: c.Z = munsellSloanGodlove((white.Z / white.X) * v->Z) - c.Y;
264:
265: return c;
266: }
267:
268: #define SQUARE(x) ((x) * (x))
269:
270: static float CIE76(Lab *L1, Lab *L2) {
271: // http://en.wikipedia.org/wiki/Color_difference#CIE76
272: float lbias = 1.0;
273: return sqrt(lbias * SQUARE(L2->L - L1->L) + SQUARE(L2->a - L1->a) + SQUARE(L2->b - L1->b));
274: }
275:
276: static void init_coersion() {
277: fcolor sRGB_white = (fcolor) {1, 1, 1};
278: white = toCIE(sRGB_white);
279:
280: int i;
281: for (i = 0; i < 16; i++) {
282: ciePalette[i] = toCIE(palette[i]);
283: labPalette[i] = toLab(&ciePalette[i]);
284: adamsPalette[i] = adams(&ciePalette[i]);
285: }
286:
287: if (colormode == coerce_256) {
288: initialize_prs();
289: }
290:
291: cell_buffer = 0;
292: }
293:
294: static int best (fcolor *fg, fcolor *bg) {
295: // analyze fg & bg for their contrast
296: CIE cieFg = toCIE(*fg);
297: CIE cieBg = toCIE(*bg);
298: Lab labFg = toLab(&cieFg);
299: Lab labBg = toLab(&cieBg);
300: // CIE adamsFg = adams(&cieFg);
301: // CIE adamsBg = adams(&cieBg);
302:
303: float JND = 2.3; // just-noticeable-difference
304: int areTheSame = CIE76(&labFg, &labBg) <= 2.0 * JND; // a little extra fudge
305:
306: float big = 100000000;
307: int fg1 = 0, fg2 = 0, bg1 = 0, bg2 = 0;
308: float fg1_score = big, fg2_score = big;
309: float bg1_score = big, bg2_score = big;
310:
311: int i;
312:
313: for (i = 0; i < 8; i++) {
314: float s = CIE76(labPalette + i, &labBg);
315:
316: if (s < bg2_score) {
317: if (s < bg1_score) {
318: bg2 = bg1; bg1 = i;
319: bg2_score = bg1_score; bg1_score = s;
320: } else {
321: bg2 = i; bg2_score = s;
322: }
323: }
324: }
325:
326: if (areTheSame) {
327: return COLORING(bg1, bg1);
328: }
329:
330: for (i = 0; i < 16; i++) {
331: float s = CIE76(labPalette + i, &labFg);
332:
333: if (s < fg2_score) {
334: if (s < fg1_score) {
335: fg2 = fg1; fg1 = i;
336: fg2_score = fg1_score; fg1_score = s;
337: } else {
338: fg2 = i; fg2_score = s;
339: }
340: }
341: }
342:
343: if (fg1 != bg1) {
344: return COLORING (fg1, bg1);
345: } else {
346: if (fg1_score + bg2_score < fg2_score + bg1_score) {
347: return COLORING(fg1, bg2);
348: } else {
349: return COLORING(fg2, bg1);
350: }
351: }
352: }
353:
354:
355:
356:
357: static void initialize_prs() {
358: int i;
359: for (i = 16; i < 255; i++) {
360: prs[i].next = i + 1;
361: }
362: prs[0].next = 16;
363: prs[1].next = 0;
364: prs[255].next = 0;
365: }
366:
367: static void coerce_colorcube (fcolor *f, intcolor *c) {
368: // 0-15 are the standard ANSI colors
369: // 16-231 are a 6x6x6 RGB color cube given by ((36 * r) + (6 * g) + b + 16) with r,g,b in [0..5]
370: // 232-255 are a greyscale ramp without black and white.
371:
372: float sat = 0.2, bright = 0.6, contrast = 6.3;
373:
374: float rf = bright + f->r * contrast,
375: gf = bright + f->g * contrast,
376: bf = bright + f->b * contrast;
377:
378: if (rf < gf && rf < bf) rf -= sat * ((gf < bf ? bf : gf) - rf);
379: else if (gf < bf && gf < rf) gf -= sat * ((rf < bf ? bf : rf) - gf);
380: else if (bf < gf && bf < rf) bf -= sat * ((gf < rf ? rf : gf) - bf);
381:
382: int r = rf, g = gf, b = bf;
383: r = r < 0 ? 0 : r > 5 ? 5 : r;
384: g = g < 0 ? 0 : g > 5 ? 5 : g;
385: b = b < 0 ? 0 : b > 5 ? 5 : b;
386:
387: c->r = r;
388: c->g = g;
389: c->b = b;
390: c->idx = ((36 * r) + (6 * g) + b + 16);
391: }
392:
393: static int intcolor_distance (intcolor *a, intcolor *b) {
394: return
395: (a->r - b->r) * (a->r - b->r)
396: + (a->g - b->g) * (a->g - b->g)
397: + (a->b - b->b) * (a->b - b->b);
398: }
399:
400: static int coerce_prs (intcolor *fg, intcolor *bg) {
401: // search for an exact match in the list
402: int pair;
403: pair = prs[1].next;
404: while (pair) {
405: if (prs[pair].fore.idx == fg->idx && prs[pair].back.idx == bg->idx) {
406: // perfect.
407: prs[pair].count++;
408: return pair;
409: }
410: pair = prs[pair].next;
411: }
412:
413: // no exact match? try to insert it as a new one
414: pair = prs[0].next;
415: if (pair) {
416: // there's room!
417:
418: // remove
419: prs[0].next = prs[pair].next;
420:
421: // insert at the front
422: prs[pair].next = prs[1].next;
423: prs[1].next = pair;
424:
425: // initialize it
426: prs[pair].fore = *fg;
427: prs[pair].back = *bg;
428: prs[pair].count = 1;
429:
430: init_pair(pair, fg->idx, bg->idx);
431:
432: return pair;
433: }
434:
435: // search for an approximate match in the list
436: int bestpair = 0, bestscore = 2 * 3 * 6 * 6; // naive distance metric for now
437: pair = prs[1].next;
438: while (pair) {
439: int delta = intcolor_distance(&prs[pair].fore, fg) + intcolor_distance(&prs[pair].back, bg);
440: if (delta < bestscore) {
441: bestscore = delta;
442: bestpair = pair;
443: if (delta == 1) break; // as good as it gets without being exact!
444: }
445: pair = prs[pair].next;
446: }
447:
448: prs[bestpair].count++;
449: return bestpair;
450: }
451:
452: static void buffer_plot(int ch, int x, int y, fcolor *fg, fcolor *bg) {
453: // int pair = 256 + x + y * minsize.width;
454: // intcolor cube_fg, cube_bg;
455: // coerce_colorcube(fg, &cube_fg),
456: // coerce_colorcube(bg, &cube_bg);
457:
458: // pair = cube_bg.idx;
459: // cube_fg = cube_bg;
460:
461:
462: // init_pair(pair, cube_fg.idx, cube_bg.idx);
463:
464: // return pair;
465:
466: intcolor cube_fg, cube_bg;
467:
468: coerce_colorcube(fg, &cube_fg);
469: coerce_colorcube(bg, &cube_bg);
470: if (cube_fg.idx == cube_bg.idx) {
471: // verify that the colors are really the same; otherwise, we'd better force the output apart
472: int naive_distance =
473: (fg->r - bg->r) * (fg->r - bg->r)
474: + (fg->g - bg->g) * (fg->g - bg->g)
475: + (fg->b - bg->b) * (fg->b - bg->b);
476: if (naive_distance > 3) {
477: // very arbitrary cutoff, and an arbitrary fix, very lazy
478: if (cube_bg.r > 0) {cube_bg.r -= 1; cube_bg.idx -= 1; }
479: if (cube_bg.g > 0) {cube_bg.g -= 1; cube_bg.idx -= 6; }
480: if (cube_bg.b > 0) {cube_bg.b -= 1; cube_bg.idx -= 36; }
481: }
482: }
483:
484: int cell = x + y * minsize.width;
485: cell_buffer[cell].ch = ch;
486: cell_buffer[cell].pair = -1;
487: cell_buffer[cell].fore = cube_fg;
488: cell_buffer[cell].back = cube_bg;
489: }
490:
491: static void buffer_render_256() {
492: // build a new palette
493: initialize_prs();
494:
495: int length = minsize.width * minsize.height;
496: int i, idx, x, y;
497:
498: for (i = 0; i < length; i++) {
499: cell_buffer[i].shuffle = i;
500: }
501: for (i = length - 1; i >= 0; i--) {
502: // int roll = i == 0 ? 0 : rand() % i;
503: // idx = cell_buffer[roll].shuffle;
504:
505: // cell_buffer[roll].shuffle = cell_buffer[i].shuffle;
506:
507: idx = i;
508:
509: int pair = coerce_prs(&cell_buffer[idx].fore, &cell_buffer[idx].back);
510: cell_buffer[idx].pair = pair;
511: }
512:
513: // render it all!
514: i = 0;
515: for (y = 0; y < minsize.height; y++) {
516: move(y, 0);
517: for (x = 0; x < minsize.width; x++) {
518: color_set(cell_buffer[i].pair, NULL);
519: addch(cell_buffer[i].ch);
520: i++;
521: }
522: }
523: }
524:
525: static void term_mvaddch(int x, int y, int ch, fcolor *fg, fcolor *bg) {
526: if (x < 0 || y < 0 || x >= minsize.width || y >= minsize.height) return;
527:
528: if (colormode == coerce_16) {
529: int c = best(fg, bg);
530: attrset(COLOR_ATTR(c));
531: mvaddch(y, x, ch);
532: } else {
533: buffer_plot(ch, x, y, fg, bg);
534: }
535: }
536:
537: static void term_refresh() {
538: // to set up a 256-color terminal, see:
539: // http://push.cx/2008/256-color-xterms-in-ubuntu
540: if (0 && can_change_color()) {
541: int i;
542: for (i = 0; i < 16; i++) {
543: short r = palette[i].r * 1000;
544: short g = palette[i].g * 1000;
545: short b = palette[i].b * 1000;
546: if (r < 0) r = 0;
547: if (g < 0) g = 0;
548: if (b < 0) b = 0;
549: init_color(i + 1, r, g, b);
550: }
551: }
552: if (0) {
553: int i;
554: short r, g, b;
555: for (i = 0; i < 8; i++) {
556: color_content(i, &r, &g, &b);
557: palette[i].r = r * .001;
558: palette[i].g = g * .001;
559: palette[i].b = b * .001;
560: }
561: }
562:
563:
564: if (colormode == coerce_256) {
565: buffer_render_256();
566: }
567:
568: refresh();
569: }
570:
571: static void ensure_size( );
572:
573: static int term_getkey( ) {
574: Term.mouse.justPressed = 0;
575: Term.mouse.justReleased = 0;
576: Term.mouse.justMoved = 0;
577:
578: while (1) {
579: int got = getch();
580: if (got == KEY_RESIZE) {
581: ensure_size( );
582: } else if (got == KEY_MOUSE) {
583: MEVENT mevent;
584: getmouse (&mevent);
585: Term.mouse.x = mevent.x;
586: Term.mouse.y = mevent.y;
587: Term.mouse.shift = (mevent.bstate & BUTTON_SHIFT) != 0;
588: Term.mouse.control = (mevent.bstate & BUTTON_CTRL) != 0;
589: if (mevent.bstate & BUTTON1_PRESSED) {
590: Term.mouse.justPressed = 1;
591: Term.mouse.isPressed = 1;
592: } else if (mevent.bstate & BUTTON1_RELEASED) {
593: if (Term.mouse.isPressed) {
594: Term.mouse.justReleased = 1;
595: Term.mouse.isPressed = 0;
596: }
597: } else {
598: Term.mouse.justMoved = 1;
599: }
600: return TERM_MOUSE;
601: } else {
602: if (got == KEY_ENTER) got = 13; // KEY_ENTER -> ^M for systems with odd values for KEY_ENTER
603: if (got == ERR) return TERM_NONE;
604: else return got;
605: }
606: }
607: }
608:
609: static int term_has_key() {
610: int ch = getch();
611: if (ch != ERR) {
612: ungetch(ch);
613: return 1;
614: } else {
615: return 0;
616: }
617: }
618:
619: static void ensure_size( ) {
620: int w = minsize.width, h = minsize.height;
621:
622: getmaxyx(stdscr, Term.height, Term.width);
623: if (Term.height < h || Term.width < w) {
624: getmaxyx(stdscr, Term.height, Term.width);
625: nodelay(stdscr, FALSE);
626: while (Term.height < h || Term.width < w) {
627: erase();
628: attrset(COLOR_ATTR(7));
629:
630: mvprintw(1,0,"Brogue needs a terminal window that is at least [%d x %d]", w, h);
631:
632: attrset(COLOR_ATTR(15));
633: mvprintw(2,0,"If your terminal can be resized, resize it now.\n");
634:
635: attrset(COLOR_ATTR(7));
636: mvprintw(3,0,"Press ctrl-c at any time to quit.\n");
637:
638: printw("Width: %d/%d\n", Term.width, w);
639: printw("Height: %d/%d\n", Term.height, h);
640:
641: mvprintw(10, 0, "Colors (pairs): %d (%d)\n", COLORS, COLOR_PAIRS);
642:
643: getch();
644: getmaxyx(stdscr, Term.height, Term.width);
645: }
646: nodelay(stdscr, TRUE);
647: erase();
648: refresh();
649: }
650: }
651:
652: static void term_resize(int w, int h) {
653: minsize.width = w;
654: minsize.height = h;
655:
656: // try to set the terminal size if the terminal will let us:
657: term_set_size(h, w);
658: // (this works in gnome-terminal, but causes trouble for curses on maximized windows.)
659:
660: // now make sure it worked, and ask the user to resize the terminal if it didn't
661: ensure_size();
662:
663:
664: // make a new cell buffer
665:
666: if (cell_buffer) free(cell_buffer);
667: cell_buffer = malloc(sizeof(pairmode_cell) * w * h);
668: // add error checking
669: int i;
670:
671: for (i = 0; i < w * h; i++) {
672: // I guess we could just zero it all, hmm
673: cell_buffer[i].ch = 0;
674: cell_buffer[i].pair = 0;
675: cell_buffer[i].fore.idx = 0;
676: cell_buffer[i].back.idx = 0;
677: }
678: }
679:
680: static void term_wait(int ms) {
681: napms(ms);
682: }
683:
684:
685: struct {
686: char *name;
687: int ch;
688: } curses_keys[] = {
689: {"NONE", TERM_NONE},
690:
691: {"TAB", '\t'},
692: {"ENTER", '\n'},
693: {"RETURN", '\n'},
694: {"SPACE", ' '},
695:
696: {"ESC", 27},
697: {"ESCAPE", 27},
698:
699: {"BREAK", KEY_BREAK},
700: {"SRESET", KEY_SRESET},
701: {"RESET", KEY_RESET},
702: {"DOWN", KEY_DOWN},
703: {"UP", KEY_UP },
704: {"LEFT", KEY_LEFT},
705: {"RIGHT", KEY_RIGHT},
706: {"HOME", KEY_HOME},
707: {"BACKSPACE", KEY_BACKSPACE},
708: {"F1", KEY_F(1)},
709: {"F2", KEY_F(2)},
710: {"F3", KEY_F(3)},
711: {"F4", KEY_F(4)},
712: {"F5", KEY_F(5)},
713: {"F6", KEY_F(6)},
714: {"F7", KEY_F(7)},
715: {"F8", KEY_F(8)},
716: {"F9", KEY_F(9)},
717: {"F10", KEY_F(10)},
718: {"F11", KEY_F(11)},
719: {"F12", KEY_F(12)},
720: {"DL", KEY_DL},
721: {"IL", KEY_IL},
722: {"DC", KEY_DC},
723: {"DEL", KEY_DC},
724: {"DELETE", KEY_DC},
725: {"IC", KEY_IC},
726: {"EIC", KEY_EIC},
727: {"CLEAR", KEY_CLEAR},
728: {"EOS", KEY_EOS},
729: {"EOL", KEY_EOL},
730: {"SF", KEY_SF},
731: {"SR", KEY_SR},
732:
733: {"PGUP", KEY_NPAGE},
734: {"PGDN", KEY_PPAGE},
735: {"PAGEDOWN", KEY_NPAGE},
736: {"PAGEUP", KEY_PPAGE},
737: {"NPAGE", KEY_NPAGE},
738: {"PPAGE", KEY_PPAGE},
739:
740: {"STAB", KEY_STAB},
741: {"CTAB", KEY_CTAB},
742: {"CATAB", KEY_CATAB},
743:
744: {"PRINT", KEY_PRINT},
745: {"LL", KEY_LL},
746: {"A1", KEY_A1},
747: {"A3", KEY_A3},
748: {"B2", KEY_B2},
749: {"C1", KEY_C1},
750: {"C3", KEY_C3},
751: {"BTAB", KEY_BTAB},
752: {"BEG", KEY_BEG },
753: {"CANCEL", KEY_CANCEL},
754: {"CLOSE", KEY_CLOSE},
755: {"COMMAND", KEY_COMMAND},
756: {"COPY", KEY_COPY},
757: {"CREATE", KEY_CREATE},
758: {"END", KEY_END },
759: {"EXIT", KEY_EXIT},
760: {"FIND", KEY_FIND},
761: {"HELP", KEY_HELP},
762: {"MARK", KEY_MARK},
763: {"MESSAGE", KEY_MESSAGE},
764: {"MOVE", KEY_MOVE},
765: {"NEXT", KEY_NEXT},
766: {"OPEN", KEY_OPEN},
767: {"OPTIONS", KEY_OPTIONS},
768: {"PREVIOUS", KEY_PREVIOUS},
769: {"REDO", KEY_REDO},
770: {"REFERENCE", KEY_REFERENCE},
771: {"REFRESH", KEY_REFRESH},
772: {"REPLACE", KEY_REPLACE},
773: {"RESTART", KEY_RESTART},
774: {"RESUME", KEY_RESUME},
775: {"SAVE", KEY_SAVE},
776: {"SBEG", KEY_SBEG},
777: {"SCANCEL", KEY_SCANCEL},
778: {"SCOMMAND", KEY_SCOMMAND},
779: {"SCOPY", KEY_SCOPY},
780: {"SCREATE", KEY_SCREATE},
781: {"SDC", KEY_SDC },
782: {"SDL", KEY_SDL },
783: {"SELECT", KEY_SELECT},
784: {"SEND", KEY_SEND},
785: {"SEOL", KEY_SEOL},
786: {"SEXIT", KEY_SEXIT},
787: {"SFIND", KEY_SFIND},
788: {"SHELP", KEY_SHELP},
789: {"SHOME", KEY_SHOME},
790: {"SIC", KEY_SIC },
791: {"SLEFT", KEY_SLEFT},
792: {"SMESSAGE", KEY_SMESSAGE},
793: {"SMOVE", KEY_SMOVE},
794: {"SNEXT", KEY_SNEXT},
795: {"SOPTIONS", KEY_SOPTIONS},
796: {"SPREVIOUS", KEY_SPREVIOUS},
797: {"SPRINT", KEY_SPRINT},
798: {"SREDO", KEY_SREDO},
799: {"SREPLACE", KEY_SREPLACE},
800: {"SRIGHT", KEY_SRIGHT},
801: {"SRSUME", KEY_SRSUME},
802: {"SSAVE", KEY_SSAVE},
803: {"SSUSPEND", KEY_SSUSPEND},
804: {"SUNDO", KEY_SUNDO},
805: {"SUSPEND", KEY_SUSPEND},
806: {"UNDO", KEY_UNDO},
807: {"MOUSE", KEY_MOUSE},
808: {"RESIZE", KEY_RESIZE},
809: {NULL, 0},
810: };
811:
812: int term_keycodeByName(const char *name) {
813: int i = 0;
814: while (curses_keys[i].name != NULL) {
815: if (strcmp(name, curses_keys[i].name) == 0) {
816: return curses_keys[i].ch;
817: }
818: i++;
819: }
820:
821: return name[0];
822: }
823:
824:
825: struct term_t Term = {
826: term_start,
827: term_end,
828: term_mvaddch,
829: term_refresh,
830: term_getkey,
831: term_wait,
832: term_has_key,
833: term_title,
834: term_resize,
835: term_keycodeByName,
836: {KEY_UP, KEY_DOWN, KEY_LEFT, KEY_RIGHT, KEY_BACKSPACE, KEY_DC, KEY_F(12)}
837: };
CVSweb