1 /* term_curses.c - Terminal screen update code; based on term_x11.c
2 
3    Copyright (c) 1997-2003, Sidik Isani (xhomer@isani.org)
4 
5    This file is part of Xhomer.
6 
7    Xhomer is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License version 2
9    as published by the Free Software Foundation.
10 
11    Xhomer is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15 
16    You should have received a copy of the GNU General Public License
17    along with Xhomer; if not, write to the Free Software
18    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19 
20  *
21  * TODO:
22  *   - Simh terminal settings are still trapping ^E.
23  *   - Suspend curses control if at the simh> prompt (see man
24  *     page for an example of how to do this.)
25  *   - Check all keyboard mappings.
26  *   - Assign alternate to CONTROL-F1 since not all text
27  *     terminals may have such a key combination (linux console is
28  *     one, for example, which cannot distinguish control-f1 and f1.)
29  *   - Suppress error messages from xhomer itself which
30  *     can corrupt the curses window.
31  *   - Implement Control-L to force a refresh in case screen
32  *     gets messed up anyway.
33  *   - Warn if terminal window is smaller than 80x24.
34  *   - Implement overlay so that underlying characters show even
35  *     if the menu is up (right now, entire screen is replaced.)
36  *   - Colors?
37  *   - Search up/down by scanlines so that Synergy works.
38  *   - ifdef-out some of the special KEY_ definitions which might
39  *     be ncurses-specific (i.e., use them only if defined, otherwise
40  *     this may fail to compile with older curses libraries.)
41  */
42 
43 #ifdef PRO
44 
45 #include <stdlib.h>
46 #include <stdio.h>
47 #include <string.h>
48 
49 #include <curses.h>
50 
51 #include "pro_defs.h"
52 #include "pro_lk201.h"
53 
54 #define	PRO_KEYBOARD_FIFO_DEPTH	1024
55 
56 #define PRO_FONT_SCANLINES 10
57 
58 /*
59  * Special key codes not defined by curses.
60  */
61 #define ESCAPE (27)
62 #define CNTR(c) (1-'A'+c)
63 #define CNTR_F1 03776 /* Any unused keycode will do. */
64 
65 
66 /* Dummy values copied from term_x11.c - required so xhomer can compile. */
67 int                     pro_nine_workaround = 0;        /* workaround for #9 Xserver bugs */
68 int                     pro_libc_workaround = 0;        /* workaround for pre-glibc-2.0 bug */
69 int			pro_window_x = 0;	/* window x position */
70 int			pro_window_y = 0;	/* window y position */
71 int			pro_screen_full = 0;	/* 0 = window, 1 = full-screen */
72 int			pro_screen_window_scale = 2;	/* vertical window scale factor */
73 int			pro_screen_full_scale = 2;	/* vertical DGA scale factor */
74 int                     pro_screen_gamma = 10;          /* 10x gamma correction factor */
75 int                     pro_screen_pcm = 1;             /* 0 = don't use PCM, 1 = use PCM (private color map) */
76 int                     pro_screen_framebuffers = 1;    /* number of DGA framebuffers (1..3)
77 							 */
78 
79 int			pro_mouse_x = 0;	/* mouse x */
80 int			pro_mouse_y = 0;	/* mouse y */
81 int			pro_mouse_l = 0;	/* left mouse button */
82 int			pro_mouse_m = 0;	/* middle mouse button */
83 int			pro_mouse_r = 0;	/* right mouse button */
84 int			pro_mouse_in = 0;	/* mouse in window */
85 
86 LOCAL int		pro_screen_blank = 0;	/* indicates whether screen is blanked */
87 
88 LOCAL WINDOW*           main_window = 0;
89 LOCAL WINDOW*           overlay_window = 0;
90 
91 LOCAL int               titlebar_ok = 0;
92 
93 /* Temporary hack for terminal types which have no "control-F1" (linux) */
94 
95 LOCAL int               f1_equals_control_f1 = 0;
96 
97 /* Put a title on the display window */
98 
pro_screen_title(char * title)99 void pro_screen_title (char *title)
100 {
101    if (titlebar_ok)
102       fprintf(stderr, "\033]2;%s\a", title);
103 }
104 
update()105 LOCAL void update ()
106 {
107    wnoutrefresh(main_window);
108    if (overlay_window)
109    {
110       touchwin(overlay_window);
111       wnoutrefresh(overlay_window);
112    }
113    doupdate();
114 }
115 
pro_screen_clear()116 void pro_screen_clear ()
117 {
118    wclear(main_window);
119    update();
120 }
121 
122 /* External keyboard polling routine */
123 
keyboard_get()124 LOCAL int keyboard_get ()
125 {
126    static int shift = 0;
127    static int ctrl = 0;
128    static int ch = ERR;
129    int shift_wanted;
130    int ctrl_wanted;
131    int c;
132 
133    while (ch==ERR)
134    {
135       static int escape = 0; /* >0 if reading an escape sequence */
136       static char escape_seq[1024];
137 
138       wnoutrefresh(main_window);
139       ch = wgetch(main_window);
140       if (f1_equals_control_f1 && ch == KEY_F(1))
141 	 ch = CNTR_F1;
142       if (escape)
143       {
144 	 escape_seq[escape-1] = ch;
145 	 if (!(('0'<=ch && ch<=';') ||
146                ch=='(' || ch=='[' || ch=='O' || ch==ESCAPE))
147 	    /* filter out escape sequences not handled by curses */
148 	 {
149 	    if (ch == ERR) escape--;
150             escape_seq[escape]='\0';
151             escape=0;
152 	    if (!strcmp(escape_seq, ""))
153 	       ch = ESCAPE;
154 	    else if (!strcmp(escape_seq, "[11^")) /* rxvt */
155 	       ch = CNTR_F1;
156 	    else if (!strcmp(escape_seq, "O5P")) /* xterm */
157 	       ch = CNTR_F1;
158 	    else if (!strcmp(escape_seq, "[[A")) /* linux, F1 */
159 	       ch = CNTR_F1;
160             else if (!strcmp(escape_seq, "[5~"))
161                ch = KEY_PPAGE;
162             else if (!strcmp(escape_seq, "[6~"))
163                ch = KEY_NPAGE;
164             else if (!strcmp(escape_seq, "[3~"))
165                ch = KEY_DC;
166             else if (!strcmp(escape_seq, "Ot"))
167                ch = KEY_LEFT;
168             else if (!strcmp(escape_seq, "Ov"))
169                ch = KEY_RIGHT;
170             else if (!strcmp(escape_seq, "Ox"))
171                ch = KEY_UP;
172             else if (!strcmp(escape_seq, "Or"))
173                ch = KEY_DOWN;
174             else
175             {
176                beep();
177 	       /* DEBUG:
178                fprintf(stderr, "Unrecognized escape sequence: `%.900s'", escape_seq);
179 	       */
180                ch = ERR;
181             }
182 	 }
183          else
184          {
185             if (escape<1022) escape++;
186          }
187       }
188       else if (ch == ESCAPE) escape = 1;
189 
190       if (ch == ERR) return PRO_NOCHAR;
191       if (escape) { ch = ERR; continue; }
192    }
193 
194    /*
195     * Check proper state of the control key
196     */
197    if (ch < ' ' || ch == CNTR_F1)
198       ctrl_wanted = 1; else ctrl_wanted = 0;
199 
200    if (ctrl_wanted && !ctrl)
201    {
202       ctrl = 1;
203       return PRO_LK201_CTRL;
204    }
205 
206    /*
207     * Check proper state of the shift key
208     */
209    if (strchr("~!@#$%^&*()_+ABCDEFGHIJKLMNOPQRSTUVWXYZ{}|:\"<>?", ch))
210       shift_wanted = 1; else shift_wanted = 0;
211 
212    if (shift_wanted && !shift)
213    {
214       shift = 1;
215       return PRO_LK201_SHIFT;
216    }
217 
218    if (shift != shift_wanted || ctrl != ctrl_wanted)
219    {
220       ctrl = 0; shift = 0;
221       return PRO_LK201_ALLUPS;
222    }
223 
224    c = ch;
225    ch = ERR;
226 
227    /* DEBUG:
228    fprintf(stderr, "\r\nctrl=%d shift=%d key=%d\r\n", ctrl, shift, c);
229    */
230 
231    switch (c)
232    {
233       case CNTR('I'): case KEY_BTAB:	  return PRO_LK201_TAB;
234       case CNTR('M'):			  return PRO_LK201_RETURN;
235       case ' ':				  return PRO_LK201_SPACE;
236       case 'a': case 'A': case CNTR('A'): return PRO_LK201_A;
237       case 'b': case 'B': case CNTR('B'): return PRO_LK201_B;
238       case 'c': case 'C': case CNTR('C'): return PRO_LK201_C;
239       case 'd': case 'D': case CNTR('D'): return PRO_LK201_D;
240       case 'e': case 'E': case CNTR('E'): return PRO_LK201_E;
241       case 'f': case 'F': case CNTR('F'): return PRO_LK201_F;
242       case 'g': case 'G': case CNTR('G'): return PRO_LK201_G;
243       case 'h': case 'H': case CNTR('H'): return PRO_LK201_H;
244       case 'i': case 'I': /* CNTR('I') */ return PRO_LK201_I;
245       case 'j': case 'J': case CNTR('J'): return PRO_LK201_J;
246       case 'k': case 'K': case CNTR('K'): return PRO_LK201_K;
247       case 'l': case 'L': case CNTR('L'): return PRO_LK201_L;
248       case 'm': case 'M': /* CNTR('M') */ return PRO_LK201_M;
249       case 'n': case 'N': case CNTR('N'): return PRO_LK201_N;
250       case 'o': case 'O': case CNTR('O'): return PRO_LK201_O;
251       case 'p': case 'P': case CNTR('P'): return PRO_LK201_P;
252       case 'q': case 'Q': case CNTR('Q'): return PRO_LK201_Q;
253       case 'r': case 'R': case CNTR('R'): return PRO_LK201_R;
254       case 's': case 'S': case CNTR('S'): return PRO_LK201_S;
255       case 't': case 'T': case CNTR('T'): return PRO_LK201_T;
256       case 'u': case 'U': case CNTR('U'): return PRO_LK201_U;
257       case 'v': case 'V': case CNTR('V'): return PRO_LK201_V;
258       case 'w': case 'W': case CNTR('W'): return PRO_LK201_W;
259       case 'x': case 'X': case CNTR('X'): return PRO_LK201_X;
260       case 'y': case 'Y': case CNTR('Y'): return PRO_LK201_Y;
261       case 'z': case 'Z': case CNTR('Z'): return PRO_LK201_Z;
262       case '`': case '~':                 return PRO_LK201_TICK;
263       case '1': case '!':                 return PRO_LK201_1;
264       case '2': case '@':                 return PRO_LK201_2;
265       case '3': case '#':                 return PRO_LK201_3;
266       case '4': case '$':                 return PRO_LK201_4;
267       case '5': case '%':                 return PRO_LK201_5;
268       case '6': case '^': case CNTR('^'): return PRO_LK201_6;
269       case '7': case '&':                 return PRO_LK201_7;
270       case '8': case '*':                 return PRO_LK201_8;
271       case '9': case '(':                 return PRO_LK201_9;
272       case '0': case ')':                 return PRO_LK201_0;
273       case '-': case '_': case CNTR('_'): return PRO_LK201_MINUS;
274       case '=': case '+':                 return PRO_LK201_EQUAL;
275       case '[': case '{': /* CNTR('[') */ return PRO_LK201_LEFTB;
276       case ']': case '}': case CNTR(']'): return PRO_LK201_RIGHTB;
277       case '\\':case '|': case CNTR('\\'):return PRO_LK201_BACKSL;
278       case ';': case ':':                 return PRO_LK201_SEMI;
279       case '\'':case '"':                 return PRO_LK201_QUOTE;
280       case ',': case '<':                 return PRO_LK201_COMMA;
281       case '.': case '>':                 return PRO_LK201_PERIOD;
282       case '/': case '?':                 return PRO_LK201_SLASH;
283       case KEY_BREAK:			  return PRO_LK201_DO; /* %%% */
284       case KEY_DOWN:			  return PRO_LK201_DOWN;
285       case KEY_UP:			  return PRO_LK201_UP;
286       case KEY_LEFT:	case KEY_SLEFT:   return PRO_LK201_LEFT;
287       case KEY_RIGHT:	case KEY_SRIGHT:  return PRO_LK201_RIGHT;
288       case KEY_HOME:	case KEY_SHOME:   return PRO_LK201_SELECT; /* %%% */
289       case KEY_BACKSPACE:		return PRO_LK201_DEL;
290       case ESCAPE:			return PRO_LK201_HOLD;
291       case CNTR_F1:
292       case KEY_F(1):			return PRO_LK201_PRINT;
293       case KEY_F(2):			return PRO_LK201_SETUP;
294       case KEY_F(3):			return PRO_LK201_FFOUR;
295       case KEY_F(4):			return PRO_LK201_BREAK;
296       case KEY_F(5):			return PRO_LK201_INT;
297       case KEY_F(6):			return PRO_LK201_RESUME;
298       case KEY_F(7):			return PRO_LK201_CANCEL;
299       case KEY_F(8):			return PRO_LK201_MAIN;
300       case KEY_F(9):			return PRO_LK201_EXIT;
301       case KEY_F(10):			return PRO_LK201_ESC;
302       case KEY_F(11):			return PRO_LK201_BS;
303       case KEY_F(12):			return PRO_LK201_LF;
304       /* %%% ADDOP, HELP, and DO! */
305       case KEY_DL:	case KEY_SDL:
306       case KEY_IL:
307       case KEY_DC:	case KEY_SDC:
308       case KEY_IC:	case KEY_SIC:
309       case KEY_EIC:
310       case KEY_CLEAR:
311       case KEY_EOS:
312       case KEY_EOL:	case KEY_SEOL:
313       case KEY_SF:
314       case KEY_SR:
315       case KEY_NPAGE:			return PRO_LK201_NEXT;
316       case KEY_PPAGE:			return PRO_LK201_PREV;
317       case KEY_STAB:
318       case KEY_CTAB:
319       case KEY_CATAB:
320       case KEY_ENTER:
321       case KEY_SRESET:
322       case KEY_RESET:
323       case KEY_PRINT:
324       case KEY_LL:
325       case KEY_A1:
326       case KEY_A3:
327       case KEY_B2:
328       case KEY_C1:
329       case KEY_C3:
330       case KEY_BEG:	case KEY_SBEG:
331       case KEY_CANCEL:	case KEY_SCANCEL:
332       case KEY_CLOSE:
333       case KEY_COMMAND:	case KEY_SCOMMAND:
334       case KEY_COPY:	case KEY_SCOPY:
335       case KEY_CREATE:	case KEY_SCREATE:
336       case KEY_END:
337       case KEY_EXIT:	case KEY_SEXIT:
338       case KEY_FIND:	case KEY_SFIND:
339       case KEY_HELP:	case KEY_SHELP:
340       case KEY_MARK:
341       case KEY_MESSAGE:	case KEY_SMESSAGE:
342       case KEY_MOVE:	case KEY_SMOVE:
343       case KEY_NEXT:	case KEY_SNEXT:
344       case KEY_OPEN:
345       case KEY_OPTIONS:	case KEY_SOPTIONS:
346       case KEY_PREVIOUS: case KEY_SPREVIOUS:
347       case KEY_REDO:	case KEY_SREDO:
348       case KEY_REFERENCE:
349       case KEY_REFRESH:
350       case KEY_REPLACE:	case KEY_SREPLACE:
351       case KEY_RESTART:
352       case KEY_RESUME:	case KEY_SRSUME:
353       case KEY_SAVE:	case KEY_SSAVE:
354       case KEY_SELECT:
355       case KEY_SEND:
356       case KEY_SUSPEND:	case KEY_SSUSPEND:
357       case KEY_UNDO:	case KEY_SUNDO:
358       default:
359 	return PRO_NOCHAR;
360    }
361 }
362 
pro_keyboard_get()363 int pro_keyboard_get ()
364 {
365    return pro_menu(keyboard_get());
366 }
367 
368 /* Initialize the display */
369 
pro_screen_init_curses()370 LOCAL int pro_screen_init_curses ()
371 {
372    static int initialized = 0;
373 
374    if (!initialized)
375    {
376       initialized = 1;
377 
378       initscr(); cbreak(); noecho(); nonl(); start_color();
379       if ((main_window = newwin(0, 0, 0, 0))==0)
380 	 return PRO_FAIL;
381    }
382    else
383    {
384       /* === TODO: Window resize stuff goes here? */
385       /* Window resize really shouldn't be allowed (texthomer requires
386        * 80x24 to work properly.)
387        */
388    }
389    leaveok(main_window, TRUE); /* Ok to leave cursor when redrawing screen */
390    nodelay(main_window, TRUE); /* wgetch() returns ERR if no chars */
391    intrflush(main_window, TRUE); /* flush input if ^C is hit */
392    keypad(main_window, TRUE); /* enable numeric keypad codes */
393    curs_set(1); /* Select small cursor */
394    curs_set(0); /* Or better still, no cursor */
395    return PRO_SUCCESS;
396 }
397 
pro_screen_init()398 int pro_screen_init ()
399 {
400    const char* term;
401    static char termvar[256];
402 
403    if (!(term=getenv("COLORTERM")) || !*term)
404       if (!(term=getenv("TERM")) || !*term)
405 	 term = "vt100";
406 
407    sprintf(termvar, "TERM=%.240s", term);
408    putenv(termvar);
409 
410    if (!strncmp(term, "xterm", 5) ||
411        !strncmp(term, "rxvt", 4))
412       titlebar_ok = 1;
413    else
414       titlebar_ok = 0;
415 
416    if (getenv("TERM") && !strncmp(getenv("TERM"), "linux", 5))
417       f1_equals_control_f1 = 1;
418 
419    if (pro_screen_init_curses()==PRO_FAIL)
420    {
421       fprintf(stderr, "pro_curses: trouble initializing ncurses.\n");
422       return PRO_FAIL;
423    }
424 
425    /* Clear image buffer */
426 
427    pro_screen_clear();
428 
429    /* Invalidate display cache */
430 
431    pro_clear_mvalid();
432 
433    return PRO_SUCCESS;
434 }
435 
436 
pro_screen_close()437 void pro_screen_close ()
438 {
439    endwin();
440 }
441 
442 /* Reset routine (called only once) */
443 
pro_screen_reset()444 void pro_screen_reset ()
445 {
446    /* %%% */
447 }
448 
449 
450 /* This function is called whenever the colormap mode changes.
451    A new X11 colormap is loaded for private colormap modes,
452    mvalid is cleared otherwise */
453 
pro_mapchange()454 void pro_mapchange ()
455 {
456    /* === TODO: Support colors with ncurses? */
457 }
458 
pro_colormap_write(int index,int rgb)459 void pro_colormap_write (int index, int rgb)
460 {
461    /* === TODO: Support colors with ncurses? */
462 }
463 
464 
465 /* This is called whenever the scroll register changes */
466 
pro_scroll()467 void pro_scroll ()
468 {
469    /* Clear entire display cache for now %%% */
470    pro_clear_mvalid();
471 }
472 
473 
474 /* This called every emulated vertical retrace */
475 
476 #include "term_fonthash_curses.c"
477 
pro_screen_update()478 void pro_screen_update ()
479 {
480    int x, y, i;
481    int vindex = vmem(0);
482    int need_update = 0;
483 
484    /* Check whether screen has been blanked */
485 
486    if ((pro_vid_p1c & PRO_VID_P1_HRS) == PRO_VID_P1_OFF)
487    {
488       if (pro_screen_blank == 0)
489       {
490 	 /* Blank the screen */
491 	 /* %%% */
492 	 pro_screen_clear();
493 	 pro_screen_blank = 1;
494       }
495    }
496    else
497    {
498       if (pro_screen_blank == 1)
499       {
500 	 /* Unblank the screen */
501 
502 	 pro_clear_mvalid();
503 	 pro_screen_blank = 0;
504       }
505    }
506 
507    /* Redraw portions of screen that have changed */
508 #ifdef TEXT_PIXEL_ZOOM
509    /* Experimental mode with 1-character per pixel */
510    for (y=0; y<PRO_VID_SCRHEIGHT; y++)
511    {
512       int invalid = 0;
513 
514       if (pro_vid_mvalid[cmem(vindex)] == 0)
515       {
516 	 pro_vid_mvalid[cmem(vindex)] = 1;
517 	 invalid = 1; /* If any row has a change, redo this line of text */
518       }
519       if (invalid)
520       {
521 	 need_update = 1;
522 	 for(i=0; i<(PRO_VID_SCRWIDTH/16); i++)
523 	 {
524 	    int vpix;
525 	    int vpixs = i * 16;
526 	    int vpixe = vpixs + 16;
527 
528 	    int vdata0 = PRO_VRAM[0][vindex+i];
529 	    int vdata1 = PRO_VRAM[1][vindex+i] << 1;
530 	    int vdata2 = PRO_VRAM[2][vindex+i] << 2;
531 
532 	    for(vpix=vpixs; vpix<vpixe; vpix++)
533 	    {
534 	       int cindex = (vdata2 & 04) | (vdata1 & 02) | (vdata0 & 01);
535 	       int color = cindex; /* pro_lut[cindex]; === */
536 
537 	       mvwaddch(main_window, y, vpix-8-2*12, color>0?'*':' ');
538 
539 	       vdata0 = vdata0 >> 1;
540 	       vdata1 = vdata1 >> 1;
541 	       vdata2 = vdata2 >> 1;
542 	    }
543 	 }
544       }
545       vindex = (vindex + (PRO_VID_SCRWIDTH/16)) & PRO_VID_VADDR_MASK;
546    }
547 #else
548    for (y=0; y<PRO_VID_SCRHEIGHT/PRO_FONT_SCANLINES; y++)
549    {
550       int vlist[PRO_FONT_SCANLINES];
551       int invalid = 0;
552 
553       for (i=0; i<10; i++) /* 10 pixel rows in each font cell */
554       {
555 	 vlist[i] = vindex;
556 	 if (!pro_vid_mvalid[cmem(vindex)])
557 	 {
558 	    pro_vid_mvalid[cmem(vindex)] = 1;
559 	    invalid = 1; /* If any row has a change, redo this line of text */
560 	 }
561 	 vindex = (vindex + (PRO_VID_SCRWIDTH/16)) & PRO_VID_VADDR_MASK;
562       }
563 
564       /* Update screen segment only if display cache is invalid */
565       /* %%% Check that PRO_VID_SCRWIDTH == PRO_VID_CLS_PIX */
566 
567       if (invalid) for (x=0; x<80; x++)
568       {
569 	 char fontcell[PRO_FONT_SCANLINES*2 + 1];
570 	 register unsigned short tmp;
571 	 int ofs;
572 
573 	 need_update = 1;
574 
575 	 /* [00000000 00001111] [11111111 22222222] [22223333 33333333] */
576 	 /* [11110000 00000000] [22222222 11111111] [33333333 33332222] */
577 #define OFS 2
578 	 fontcell[PRO_FONT_SCANLINES*2] = '\0';
579 	 switch (x % 4)
580 	 {
581 	    case 0:
582 	    {
583 	       for (i=0; i<PRO_FONT_SCANLINES; i++)
584 	       {
585 		  ofs = vlist[i] + OFS + (x/4)*3;
586 		  tmp = PRO_VRAM[0][ofs];
587 		  fontcell[i*2]   = '0' + ((tmp) & 0x3F);
588 		  fontcell[i*2+1] = '0' + ((tmp >> 6) & 0x3F);
589 	       }
590 	       break;
591 	    }
592 	    case 1:
593 	    {
594 	       for (i=0; i<PRO_FONT_SCANLINES; i++)
595 	       {
596 		  ofs = vlist[i] + OFS + (x/4)*3;
597 		  tmp = PRO_VRAM[0][ofs+1];
598 		  fontcell[i*2+1] = '0' + ((tmp >> 2) & 0x3F);
599 		  tmp <<= 4;
600 		  tmp |= (PRO_VRAM[0][ofs]>>12);
601 		  fontcell[i*2]   = '0' + ((tmp) & 0x3F);
602 	       }
603 	       break;
604 	    }
605 	    case 2:
606 	    {
607 	       for (i=0; i<PRO_FONT_SCANLINES; i++)
608 	       {
609 		  ofs = vlist[i] + OFS + (x/4)*3;
610 		  tmp = PRO_VRAM[0][ofs+1];
611 		  fontcell[i*2]   = '0' + ((tmp >> 8) & 0x3F);
612 		  tmp >>= 14;
613 		  tmp |= (PRO_VRAM[0][ofs+2]<<2);
614 		  fontcell[i*2+1] = '0' + ((tmp) & 0x3F);
615 	       }
616 	       break;
617 	    }
618 	    case 3:
619 	    {
620 	       for (i=0; i<PRO_FONT_SCANLINES; i++)
621 	       {
622 		  ofs = vlist[i] + OFS + (x/4)*3;
623 		  tmp = PRO_VRAM[0][ofs+2];
624 		  fontcell[i*2]   = '0' + ((tmp >> 4) & 0x3F);
625 		  fontcell[i*2+1] = '0' + ((tmp >> 10) & 0x3F);
626 	       }
627 	       break;
628 	    }
629 	 }
630 	 {
631 	    int hashed = hash(fontcell);
632 	    int bold = 0, reverse = 0;
633 
634 	    if (hashed > 511) { hashed -= 512; reverse=1; }
635 	    if (hashed > 255) { hashed -= 256; bold=1; }
636 	    switch (hashed)
637 	    {
638 	       case 0: hashed = ' '; break;
639 	       case 30: hashed = ACS_BLOCK; break;
640 	       case 128: hashed = ACS_DIAMOND; break;
641 	       case 129: hashed = ACS_CKBOARD; break;
642 	       case 134: hashed = ACS_DEGREE; break;
643 	       case 135: hashed = ACS_PLMINUS; break;
644 	       case 138: hashed = ACS_LRCORNER; break;
645 	       case 139: hashed = ACS_URCORNER; break;
646 	       case 140: hashed = ACS_ULCORNER; break;
647 	       case 141: hashed = ACS_LLCORNER; break;
648 	       case 142: hashed = ACS_PLUS; break;
649 	       case 143: hashed = ACS_S1; break;
650 #ifdef ACS_S3
651 	       case 144: hashed = ACS_S3; break;
652 #endif
653 	       case 145: hashed = ACS_HLINE; break;
654 #ifdef ACS_S7
655 	       case 146: hashed = ACS_S7; break;
656 #endif
657 	       case 147: hashed = ACS_S9; break;
658 	       case 148: hashed = ACS_LTEE; break;
659 	       case 149: hashed = ACS_RTEE; break;
660 	       case 150: hashed = ACS_BTEE; break;
661 	       case 151: hashed = ACS_TTEE; break;
662 	       case 152: hashed = ACS_VLINE; break;
663 #ifdef ACS_LEQUAL
664 	       case 153: hashed = ACS_LEQUAL; break;
665 #endif
666 #ifdef ACS_GEQUAL
667 	       case 154: hashed = ACS_GEQUAL; break;
668 #endif
669 #ifdef ACS_PI
670 	       case 155: hashed = ACS_PI; break;
671 #endif
672 #ifdef ACS_NEQUAL
673 	       case 156: hashed = ACS_NEQUAL; break;
674 #endif
675 #ifdef ACS_STERLING
676 	       case 157: hashed = ACS_STERLING; break;
677 #endif
678 	       case 158: hashed = ACS_BULLET; break;
679 	       default: if (hashed < ' ' || hashed > '~') hashed = '#';
680 	    }
681 	    mvwaddch(main_window, y, x, hashed|(bold?A_BOLD:0)|(reverse?A_REVERSE:0));
682 	 }
683       }
684    }
685 #endif
686 
687    /* Flush the changes to the screen */
688 
689    if (need_update) update();
690 }
691 
692 
693 /* Set keyboard bell volume */
694 
pro_keyboard_bell_vol(int vol)695 void pro_keyboard_bell_vol (int vol)
696 {
697    /* Not implemented for curses */
698 }
699 
700 
701 /* Sound keyboard bell */
702 
pro_keyboard_bell()703 void pro_keyboard_bell ()
704 {
705    fputc('\a', stderr);
706 }
707 
708 
709 /* Turn off auto-repeat */
710 
pro_keyboard_auto_off()711 void pro_keyboard_auto_off ()
712 {
713    /* Not implemented for curses */
714 }
715 
716 
717 /* Turn on auto-repeat */
718 
pro_keyboard_auto_on()719 void pro_keyboard_auto_on ()
720 {
721    /* Not implemented for curses */
722 }
723 
724 
725 /* Turn off keyclick */
726 
pro_keyboard_click_off()727 void pro_keyboard_click_off ()
728 {
729    /* Not implemented for curses */
730 }
731 
732 
733 /* Turn on keyclick */
734 
pro_keyboard_click_on()735 void pro_keyboard_click_on ()
736 {
737    /* Not implemented for curses */
738 }
739 
pro_overlay_print(int x,int y,int xnor,int font,char * text)740 void pro_overlay_print(int x, int y, int xnor, int font, char *text)
741 {
742    if (!overlay_window) return;
743    if (font) wattron(overlay_window, A_BOLD);
744    wmove(overlay_window, y, x);
745    for (; *text; text++)
746    {
747       if (*text == ' ' && xnor==1)
748       {
749 	 chtype ch = winch(overlay_window);
750 	 waddch(overlay_window, ch^A_REVERSE);
751       }
752       else if (' ' <= *text && *text <= '~')
753       {
754 	 waddch(overlay_window, *text);
755       }
756       else switch (*text)
757       {
758 	 case 24: waddch(overlay_window, ACS_ULCORNER); break;
759 	 case 25:
760 	 case 29: waddch(overlay_window, ACS_HLINE); break;
761 	 case 26: waddch(overlay_window, ACS_URCORNER); break;
762 	 case 27:
763 	 case 31: waddch(overlay_window, ACS_VLINE); break;
764 	 case 30: waddch(overlay_window, ACS_LLCORNER); break;
765 	 case 28: waddch(overlay_window, ACS_LRCORNER); break;
766 	 default: waddch(overlay_window, ACS_BLOCK);
767       }
768    }
769    if (font) wattroff(overlay_window, A_BOLD);
770    update();
771    return;
772 }
773 
pro_overlay_disable()774 void pro_overlay_disable ()
775 {
776    if (!overlay_window) return;
777    delwin(overlay_window);
778    overlay_window = 0;
779    touchwin(main_window);
780    update();
781 }
782 
pro_overlay_enable()783 void pro_overlay_enable ()
784 {
785    pro_overlay_disable();
786    overlay_window = newwin(0, 0, 0, 0);
787 }
788 
789 #endif
790