1
2 /*
3 * curses.c
4 *
5 * Written by Max Khon <fjoe@iclub.nsu.ru> et al and released to the public
6 * domain.
7 *
8 * Screen definitions & routines using [n]curses.
9 */
10
11 #ifdef USE_CURSES
12
13 #include <sys/types.h>
14 #include <sys/time.h>
15 #include <ctype.h>
16 #include <ncurses.h>
17 #include <stdio.h>
18 #include <string.h>
19 #include <stdlib.h>
20 #include <unistd.h>
21
22 #include "winsys.h"
23 #include "unused.h"
24 #include "keys.h"
25 #include "readtc.h"
26 #include "specch.h"
27
28 int color;
29 int vrow, vcol;
30 int cur_start = 0;
31 int cur_end = 0;
32 static unsigned char *allowed_special_characters = NULL;
33
34 #ifdef UNIX
35 volatile
36 #endif
37 TERM term =
38 {
39 80,
40 24,
41 0
42 };
43
44 static int tcflags = 0; /* what we want to extract from termcap */
45
46 #define EBUFSZ 100
47 static EVT EVent[EBUFSZ]; /* event circular queue */
48 static int ebufin = 0; /* event in */
49 static int ebufout = 0; /* event out */
50
51 static int kbhit(void);
52
53 static int norefresh = 0;
54
ttrefresh(void)55 static void ttrefresh(void)
56 {
57 if (!norefresh)
58 {
59 refresh();
60 }
61 }
62
TTBeginOutput(void)63 void TTBeginOutput(void)
64 {
65 norefresh++;
66 }
67
TTEndOutput(void)68 void TTEndOutput(void)
69 {
70 if (norefresh)
71 {
72 norefresh--;
73 ttrefresh();
74 }
75 }
76
77
78 /* This maps PC colors to monochrome attributes for w/o color support */
79 static int mono_colors[128]=
80 {
81 A_NORMAL, A_NORMAL, A_NORMAL, A_NORMAL,
82 A_NORMAL, A_NORMAL, A_NORMAL, A_NORMAL,
83 A_BOLD, A_BOLD, A_BOLD, A_BOLD,
84 A_BOLD, A_BOLD, A_BOLD, A_BOLD,
85
86 A_REVERSE, A_REVERSE, A_REVERSE, A_REVERSE,
87 A_REVERSE, A_REVERSE, A_REVERSE, A_REVERSE,
88 A_BOLD | A_REVERSE, A_BOLD | A_REVERSE, A_BOLD | A_REVERSE, A_BOLD | A_REVERSE,
89 A_BOLD | A_REVERSE, A_BOLD | A_REVERSE, A_BOLD | A_REVERSE, A_BOLD | A_REVERSE,
90
91 A_REVERSE, A_REVERSE, A_REVERSE, A_REVERSE,
92 A_REVERSE, A_REVERSE, A_REVERSE, A_REVERSE,
93 A_BOLD | A_REVERSE, A_BOLD | A_REVERSE, A_BOLD | A_REVERSE, A_BOLD | A_REVERSE,
94 A_BOLD | A_REVERSE, A_BOLD | A_REVERSE, A_BOLD | A_REVERSE, A_BOLD | A_REVERSE,
95
96 A_REVERSE, A_REVERSE, A_REVERSE, A_REVERSE,
97 A_REVERSE, A_REVERSE, A_REVERSE, A_REVERSE,
98 A_BOLD | A_REVERSE, A_BOLD | A_REVERSE, A_BOLD | A_REVERSE, A_BOLD | A_REVERSE,
99 A_BOLD | A_REVERSE, A_BOLD | A_REVERSE, A_BOLD | A_REVERSE, A_BOLD | A_REVERSE,
100
101 A_REVERSE, A_REVERSE, A_REVERSE, A_REVERSE,
102 A_REVERSE, A_REVERSE, A_REVERSE, A_REVERSE,
103 A_BOLD | A_REVERSE, A_BOLD | A_REVERSE, A_BOLD | A_REVERSE, A_BOLD | A_REVERSE,
104 A_BOLD | A_REVERSE, A_BOLD | A_REVERSE, A_BOLD | A_REVERSE, A_BOLD | A_REVERSE,
105
106 A_REVERSE, A_REVERSE, A_REVERSE, A_REVERSE,
107 A_REVERSE, A_REVERSE, A_REVERSE, A_REVERSE,
108 A_BOLD | A_REVERSE, A_BOLD | A_REVERSE, A_BOLD | A_REVERSE, A_BOLD | A_REVERSE,
109 A_BOLD | A_REVERSE, A_BOLD | A_REVERSE, A_BOLD | A_REVERSE, A_BOLD | A_REVERSE,
110
111 A_REVERSE, A_REVERSE, A_REVERSE, A_REVERSE,
112 A_REVERSE, A_REVERSE, A_REVERSE, A_REVERSE,
113 A_BOLD | A_REVERSE, A_BOLD | A_REVERSE, A_BOLD | A_REVERSE, A_BOLD | A_REVERSE,
114 A_BOLD | A_REVERSE, A_BOLD | A_REVERSE, A_BOLD | A_REVERSE, A_BOLD | A_REVERSE,
115
116 A_REVERSE, A_REVERSE, A_REVERSE, A_REVERSE,
117 A_REVERSE, A_REVERSE, A_REVERSE, A_REVERSE,
118 A_BOLD | A_REVERSE, A_BOLD | A_REVERSE, A_BOLD | A_REVERSE, A_BOLD | A_REVERSE,
119 A_BOLD | A_REVERSE, A_BOLD | A_REVERSE, A_BOLD | A_REVERSE, A_BOLD | A_REVERSE,
120 };
121
TTScolor(unsigned int newcolor)122 int TTScolor(unsigned int newcolor)
123 {
124 int attr = 0;
125
126 color = newcolor;
127 if (!has_colors())
128 {
129 attr = mono_colors[color & 0x7F];
130 }
131 else
132 {
133 if (color & 0x08)
134 attr |= A_DIM | A_BOLD;
135 if (color & 0x80)
136 attr |= A_BLINK;
137 attr |= COLOR_PAIR(((color & 0x07) | ((color & 0x70) >> 1)));
138 }
139
140 #ifdef A_ALTCHARSET
141 if (color & F_ALTERNATE)
142 {
143 attr |= A_ALTCHARSET;
144 }
145 #endif
146
147 attrset(attr);
148 bkgdset(attr & (~A_ALTCHARSET));
149
150 return 1;
151 }
152
TTCurSet(int st)153 int TTCurSet(int st)
154 {
155 if (st)
156 curs_set(1);
157 else
158 curs_set(0);
159 return 0;
160 }
161
TTgotoxy(int row,int col)162 int TTgotoxy(int row, int col)
163 {
164 move(vrow = row, vcol = col);
165 ttrefresh();
166 return 1;
167 }
168
TTgetxy(int * row,int * col)169 int TTgetxy(int* row, int* col)
170 {
171 *row = vrow;
172 *col = vcol;
173 return 1;
174 }
175
TTPutChr(unsigned int ch)176 int TTPutChr(unsigned int ch)
177 {
178 move(vrow, vcol);
179 addch(ch);
180 ttrefresh();
181 return 1;
182 }
183
TTWriteStr(unsigned long * b,int len,int row,int col)184 int TTWriteStr(unsigned long *b, int len, int row, int col)
185 {
186 int oldcol = color;
187 int cut = 0;
188
189 move(row, col);
190 for (; len; len--, b++)
191 {
192 int ch = (int) (*b & 0x000000ffUL);
193 int col = (int)((*b & 0xffff0000UL) >> 16);
194 int y, i;
195
196 /* control chars are written in ^X notation */
197 if (ch < ' ')
198 {
199 switch (ch)
200 {
201 case '\t':
202 getyx(stdscr, y, i);
203 i = ((y >> 3) + 1) << 3;
204 cut += i-y;
205 len -= i-y;
206 break;
207
208 case '\n':
209 case '\r':
210 len += cut;
211 cut = 0;
212 break;
213
214 case '\b':
215 if (cut > 0)
216 {
217 len++;
218 cut--;
219 }
220 break;
221
222 default:
223 len--;
224 cut++;
225 }
226 }
227
228 if (color != col)
229 TTScolor(col);
230 addch(ch);
231 }
232
233 if (color != oldcol)
234 TTScolor(oldcol);
235 move(vrow, vcol);
236
237 ttrefresh();
238
239 return 1;
240 }
241
TTStrWr(unsigned char * s,int row,int col,int len)242 int TTStrWr(unsigned char *s, int row, int col, int len)
243 {
244 int cut = 0;
245 int y,i;
246
247 if (s == NULL)
248 return 1;
249
250 if (len < 0)
251 len = strlen((const char *)s);
252
253 if (len == 0)
254 return 1;
255
256 move(row, col);
257 for ( ; len; len--, s++)
258 {
259 /* control chars are written in ^X notation */
260 if (*s < ' ')
261 {
262 switch (*s)
263 {
264 case '\t':
265 getyx(stdscr, y, i);
266 i = ((y >> 3) + 1) << 3;
267 cut += i-y;
268 len -= i-y;
269 break;
270
271 case '\n':
272 case '\r':
273 len += cut;
274 cut = 0;
275 break;
276
277 case '\b':
278 if (cut > 0)
279 {
280 len++;
281 cut--;
282 }
283 break;
284
285 default:
286 len--;
287 cut++;
288 }
289 }
290
291 addch(*s);
292 }
293
294 move(vrow, vcol);
295 ttrefresh();
296 return 1;
297 }
298
TTReadStr(unsigned long * b,int len,int row,int col)299 int TTReadStr(unsigned long *b, int len, int row, int col)
300 {
301 while(len--)
302 {
303 int ch;
304 unsigned long cell;
305
306 ch = mvinch(row, col);
307 cell = ch & A_CHARTEXT;
308 if (ch & (A_DIM | A_BOLD))
309 cell |= 0x080000;
310 if (ch & A_BLINK)
311 cell |= 0x800000;
312 if (ch & A_ALTCHARSET)
313 cell |= (((unsigned long)F_ALTERNATE) << 16);
314 cell |= (((ch & 0x0700) | ((ch & 0x7000) << 1))) << 8;
315
316 *b++ = cell;
317 col++;
318 }
319 move(vrow, vcol);
320 ttrefresh();
321 return 1;
322 }
323
TTScroll(int x1,int y1,int x2,int y2,int lines,int dir)324 int TTScroll(int x1, int y1, int x2, int y2, int lines, int dir)
325 {
326 #if 0
327 /*
328 * XXX If you can make this work - mail me
329 * XXX (Seems that TTClear doesn't work properly too)
330 */
331 int height = y2-y1+1;
332 WINDOW* win;
333
334 win = subwin(stdscr, height, x2-x1+1, y1, x1);
335 if (win == NULL)
336 return 0;
337 scrollok(win, TRUE);
338 wscrl(win, dir ? lines : -lines);
339 touchline(stdscr, y1, height);
340 wttrefresh(win);
341 delwin(win);
342 #else
343 int y;
344 int width = x2 - x1 + 1;
345 unsigned long* buf;
346
347 if (lines <= 0)
348 return 0;
349
350 buf = malloc(width*sizeof(unsigned long));
351 if (buf == NULL)
352 return 0;
353
354 if (dir)
355 {
356 for (y = y1+lines; y <= y2; y++)
357 {
358 TTReadStr(buf, width, y, x1);
359 TTWriteStr(buf, width, y-lines, x1);
360 }
361
362 /* fill new lines with spaces */
363 TTClear(x1, y2-lines+1, x2, y2);
364 }
365 else
366 {
367 for (y = y2-lines; y >= y1; y--)
368 {
369 TTReadStr(buf, width, y, x1);
370 TTWriteStr(buf, width, y+lines, x1);
371 }
372
373 /* fill new lines with spaces */
374 TTClear(x1, y1, x2, y1+lines-1);
375 }
376 free(buf);
377 move(vrow, vcol);
378 ttrefresh();
379 #endif
380 return 1;
381 }
382
TTClear(int x1,int y1,int x2,int y2)383 int TTClear(int x1, int y1, int x2, int y2)
384 {
385 #if 0
386 int height = y2 - y1 + 1;
387 WINDOW* win;
388
389 win = subwin(stdscr, height, x2 - x1 + 1, y1, x1);
390 if (win == NULL)
391 return 0;
392 werase(win);
393 touchline(stdscr, y1, height);
394 wttrefresh(win);
395 delwin(win);
396 #else
397 int y;
398
399 for (y = y1; y <= y2; y++)
400 {
401 int x;
402 move(y, x1);
403 for (x = x1; x <= x2; x++)
404 addch(' ');
405 }
406 move(vrow, vcol);
407 ttrefresh();
408 #endif
409 return 1;
410 }
411
TTEeol(void)412 int TTEeol(void)
413 {
414 move(vrow, vcol);
415 clrtoeol();
416 move(vrow, vcol);
417 ttrefresh();
418 return 1;
419 }
420
TTdelay(int mil)421 int TTdelay(int mil)
422 {
423 unused(mil);
424 return 0;
425 }
426
427 static unsigned meta_alphas[] =
428 {
429 Key_A_A, Key_A_B, Key_A_C, Key_A_D, Key_A_E, Key_A_F, Key_A_G,
430 Key_A_H, Key_A_I, Key_A_J, Key_A_K, Key_A_L, Key_A_M, Key_A_N,
431 Key_A_O, Key_A_P, Key_A_Q, Key_A_R, Key_A_S, Key_A_T, Key_A_U,
432 Key_A_V, Key_A_W, Key_A_X, Key_A_Y, Key_A_Z
433 };
434
435 static unsigned meta_digits[] =
436 {
437 Key_A_0, Key_A_1, Key_A_2, Key_A_3, Key_A_4,
438 Key_A_5, Key_A_6, Key_A_7, Key_A_8, Key_A_9
439 };
440
441 void TTSendMsg(int msg, int x, int y, int msgtype);
442
TTGetKey(void)443 unsigned int TTGetKey(void)
444 {
445 int ch;
446
447 ch = getch();
448 switch (ch)
449 {
450 case KEY_RESIZE:
451 term.NRow = getmaxy(stdscr);
452 term.NCol = getmaxx(stdscr);
453 TTSendMsg(1, 0, 0, WND_WM_RESIZE);
454 return -1;
455 case KEY_LEFT:
456 return Key_Lft;
457 case KEY_RIGHT:
458 return Key_Rgt;
459 case KEY_UP:
460 return Key_Up;
461 case KEY_DOWN:
462 return Key_Dwn;
463 case KEY_BACKSPACE:
464 return Key_BS;
465 case KEY_NPAGE:
466 return Key_PgDn;
467 case KEY_PPAGE:
468 return Key_PgUp;
469 case KEY_HOME:
470 return Key_Home;
471 case KEY_END:
472 return Key_End;
473 case KEY_F(1):
474 return Key_F1;
475 case KEY_F(2):
476 return Key_F2;
477 case KEY_F(3):
478 return Key_F3;
479 case KEY_F(4):
480 return Key_F4;
481 case KEY_F(5):
482 return Key_F5;
483 case KEY_F(6):
484 return Key_F6;
485 case KEY_F(7):
486 return Key_F7;
487 case KEY_F(8):
488 return Key_F8;
489 case KEY_F(9):
490 return Key_F9;
491 case KEY_F(10):
492 return Key_F10;
493 case KEY_F(11):
494 return 0x1b; /* DEC mode ... <grin> */
495 case 0x1b:
496 halfdelay(1);
497 ch = getch();
498 nocbreak();
499 cbreak();
500 switch (tolower(ch))
501 {
502 case ERR:
503 case 0x1b:
504 return 0x1b;
505 case 'a':
506 return Key_A_A;
507 case 'b':
508 return Key_A_B;
509 case 'c':
510 return Key_A_C;
511 case 'd':
512 return Key_A_D;
513 case 'e':
514 return Key_A_E;
515 case 'f':
516 return Key_A_F;
517 case 'g':
518 return Key_A_G;
519 case 'h':
520 return Key_A_H;
521 case 'i':
522 return Key_A_I;
523 case 'j':
524 return Key_A_J;
525 case 'k':
526 return Key_A_K;
527 case 'l':
528 return Key_A_L;
529 case 'm':
530 return Key_A_M;
531 case 'n':
532 return Key_A_N;
533 case 'o':
534 return Key_A_O;
535 case 'p':
536 return Key_A_P;
537 case 'q':
538 return Key_A_Q;
539 case 'r':
540 return Key_A_R;
541 case 's':
542 return Key_A_S;
543 case 't':
544 return Key_A_T;
545 case 'u':
546 return Key_A_U;
547 case 'v':
548 return Key_A_V;
549 case 'w':
550 return Key_A_W;
551 case 'x':
552 return Key_A_X;
553 case 'y':
554 return Key_A_Y;
555 case 'z':
556 return Key_A_Z;
557 case '1':
558 return Key_F1;
559 case '2':
560 return Key_F2;
561 case '3':
562 return Key_F3;
563 case '4':
564 return Key_F4;
565 case '5':
566 return Key_F5;
567 case '6':
568 return Key_F6;
569 case '7':
570 return Key_F7;
571 case '8':
572 return Key_F8;
573 case '9':
574 return Key_F9;
575 case '0':
576 return Key_F10;
577 }
578 break;
579 }
580
581 if (ch >= 127) /* Treat special characters */
582 {
583 int assume_meta_key = 1;
584
585 /* if the character has not been explicitly */
586 /* enabled by the user, we check if it is a */
587 /* Meta keystroke. */
588
589 if (allowed_special_characters != NULL)
590 {
591 if (strchr((char*)allowed_special_characters, ch) != NULL)
592 {
593 assume_meta_key = 0;
594 }
595 }
596
597 if (assume_meta_key)
598 {
599 if (ch == 127)
600 {
601 if (wnd_bs_127)
602 {
603 ch = Key_BS;
604 }
605 else
606 {
607 ch = Key_Del;
608 }
609 }
610 else if (isalpha(ch - 128))
611 {
612 ch = meta_alphas[tolower(ch - 128) - 'a'];
613 }
614 else if (isdigit(ch - 128))
615 {
616 ch = meta_digits[ch - 128 - '0'];
617 }
618 }
619 }
620
621 return ch;
622 }
623
TTSendMsg(int msg,int x,int y,int msgtype)624 void TTSendMsg(int msg, int x, int y, int msgtype)
625 {
626 if (((ebufin + 1) % EBUFSZ) != ebufout)
627 {
628 EVent[ebufin].msg = msg;
629 EVent[ebufin].x = x;
630 EVent[ebufin].y = y;
631 EVent[ebufin].msgtype = msgtype;
632 ebufin = (ebufin + 1) % EBUFSZ;
633 }
634 }
635
TTkopen(void)636 int TTkopen(void)
637 {
638 nonl();
639 noecho();
640 cbreak();
641 nodelay(stdscr, FALSE);
642 keypad(stdscr, TRUE);
643 meta(stdscr, TRUE);
644 intrflush(stdscr, FALSE);
645 raw();
646 query_termcap(tcflags);
647 return 0;
648 }
649
TTkclose(void)650 int TTkclose(void)
651 {
652 return 0;
653 }
654
MouseOFF(void)655 void MouseOFF(void)
656 {
657 }
658
MouseON(void)659 void MouseON(void)
660 {
661 }
662
MouseInit(void)663 void MouseInit(void)
664 {
665 }
666
GetMouInfo(int * x,int * y)667 int GetMouInfo(int *x, int *y)
668 {
669 unused(x);
670 unused(y);
671 return 0;
672 }
673
674 static void
collect_events(void)675 collect_events(void)
676 {
677 int ch = TTGetKey();
678 if (ch < 0)
679 return;
680
681 TTSendMsg(ch, 0, 0, WND_WM_CHAR);
682 }
683
TTGetMsg(EVT * e)684 int TTGetMsg(EVT * e)
685 {
686 while (ebufin == ebufout)
687 collect_events();
688
689 e->msg = EVent[ebufout].msg;
690 e->x = EVent[ebufout].x;
691 e->y = EVent[ebufout].y;
692 e->msgtype = EVent[ebufout].msgtype;
693 e->id = 0;
694 ebufout = (ebufout + 1) % EBUFSZ;
695 return e->msg;
696 }
697
TTPeekQue(void)698 int TTPeekQue(void)
699 {
700 if (kbhit())
701 collect_events();
702 return ebufin != ebufout;
703 }
704
TTClearQue(void)705 void TTClearQue(void)
706 {
707 ebufin = ebufout;
708 }
709
TTGetChr(void)710 int TTGetChr(void)
711 {
712 EVT e;
713 TTGetMsg(&e);
714 return e.msg;
715 }
716
717 static char ansi2curses[8] = {
718 COLOR_BLACK,
719 COLOR_BLUE,
720 COLOR_GREEN,
721 COLOR_CYAN,
722 COLOR_RED,
723 COLOR_MAGENTA,
724 COLOR_YELLOW,
725 COLOR_WHITE
726 };
727
TTopen(void)728 int TTopen(void)
729 {
730 int i;
731
732 initscr();
733
734 color = 0x07;
735 vrow = vcol = 0;
736 term.NRow = getmaxy(stdscr);
737 term.NCol = getmaxx(stdscr);
738
739 if (has_colors())
740 {
741 start_color();
742
743 for (i = 0; i < COLOR_PAIRS; i++)
744 init_pair(i, ansi2curses[i & 0x07],
745 ansi2curses[(i & 0x38) >> 3]);
746 init_color(COLOR_RED, 0, 0, 1000);
747 init_color(COLOR_BLUE, 1000, 0, 0);
748 }
749
750 TTkopen();
751 return 1;
752 }
753
754 /*
755 * Configure the terminal. Configuration is retained even after TTclose.
756 *
757 * The ANSI/VT100 terminal accepts the following configuration keywords:
758 *
759 * keyword possible values
760 *
761 * highascii A string of high ascii bytes that, if read from the key-
762 * board shall be reported verbatim to the calling application
763 * instead of being interpreted as combination of the Meta key
764 * with a low ASCII key. You will need to enable high ascii
765 * alphabet characters (like umlauts or cyrillics) with this.
766 * An empty string is the deafault.
767 *
768 * pseudographics Not processed here - currently to psg support for curses.
769 *
770 */
771
TTconfigure(const char * keyword,const char * value)772 int TTconfigure(const char *keyword, const char *value)
773 {
774 size_t l;
775
776 if (!strcmp(keyword,"highascii"))
777 {
778 if (allowed_special_characters != NULL)
779 {
780 free(allowed_special_characters);
781 }
782 allowed_special_characters =
783 (unsigned char *) malloc(l = (strlen(value) + 1));
784 memcpy(allowed_special_characters, value, l);
785 }
786 else if (!strcmp(keyword,"pseudographics"))
787 {
788 if (atoi(value))
789 {
790 tcflags |= QUERY_ALTCHARSET;
791 }
792 else
793 {
794 tcflags &= ~QUERY_ALTCHARSET;
795 }
796 query_termcap(tcflags);
797 }
798 else
799 {
800 return 0;
801 }
802 return 1;
803 }
804
TTclose(void)805 int TTclose(void)
806 {
807 TTkclose();
808 endwin();
809 return 1;
810 }
811
kbhit(void)812 static int kbhit(void)
813 {
814 fd_set select_set;
815 struct timeval timeout;
816 FD_ZERO(&select_set);
817 FD_SET(0, &select_set);
818 timeout.tv_sec = 0;
819 timeout.tv_usec = 0;
820 select(FD_SETSIZE, &select_set, 0, 0, &timeout);
821 return FD_ISSET(0, &select_set);
822 }
823
dv_running(void)824 int dv_running(void)
825 {
826 return 0;
827 }
828
829 #endif
830