ncurses 5.7 - patch 20091107
[ncurses.git] / ncurses / win32con / win_driver.c
1 /****************************************************************************
2  * Copyright (c) 1998-2008,2009 Free Software Foundation, Inc.              *
3  *                                                                          *
4  * Permission is hereby granted, free of charge, to any person obtaining a  *
5  * copy of this software and associated documentation files (the            *
6  * "Software"), to deal in the Software without restriction, including      *
7  * without limitation the rights to use, copy, modify, merge, publish,      *
8  * distribute, distribute with modifications, sublicense, and/or sell       *
9  * copies of the Software, and to permit persons to whom the Software is    *
10  * furnished to do so, subject to the following conditions:                 *
11  *                                                                          *
12  * The above copyright notice and this permission notice shall be included  *
13  * in all copies or substantial portions of the Software.                   *
14  *                                                                          *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS  *
16  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF               *
17  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.   *
18  * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,   *
19  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR    *
20  * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR    *
21  * THE USE OR OTHER DEALINGS IN THE SOFTWARE.                               *
22  *                                                                          *
23  * Except as contained in this notice, the name(s) of the above copyright   *
24  * holders shall not be used in advertising or otherwise to promote the     *
25  * sale, use or other dealings in this Software without prior written       *
26  * authorization.                                                           *
27  ****************************************************************************/
28
29 /****************************************************************************
30  *  Author: Juergen Pfeifer                                                 *
31  *                                                                          *
32  ****************************************************************************/
33
34 #include <curses.priv.h>
35
36 MODULE_ID("$Id: win_driver.c,v 1.3 2009/11/07 16:06:42 tom Exp $")
37
38 static bool drv_CanHandle(TERMINAL_CONTROL_BLOCK * TCB, const char *tname, int *);
39 static void drv_init(TERMINAL_CONTROL_BLOCK *);
40 static void drv_release(TERMINAL_CONTROL_BLOCK *);
41 static int drv_size(TERMINAL_CONTROL_BLOCK *, int *, int *);
42 static int drv_sgmode(TERMINAL_CONTROL_BLOCK * TCB,
43                       bool setFlag,
44                       TTY * buf);
45 static chtype drv_conattr(TERMINAL_CONTROL_BLOCK * TCB);
46
47 static int drv_mvcur(TERMINAL_CONTROL_BLOCK * TCB,
48                      int yold, int xold, int ynew, int xnew);
49 static int drv_mode(TERMINAL_CONTROL_BLOCK * TCB,
50                     bool progFlag, bool defFlag);
51 static bool drv_rescol(TERMINAL_CONTROL_BLOCK * TCB);
52 static bool drv_rescolors(TERMINAL_CONTROL_BLOCK * TCB);
53 static void drv_setcolor(TERMINAL_CONTROL_BLOCK * TCB,
54                          bool fore,
55                          int color,
56                          int (*outc) (SCREEN *, int));
57 static int drv_dobeepflash(TERMINAL_CONTROL_BLOCK * TCB, bool);
58 static void drv_initpair(TERMINAL_CONTROL_BLOCK * TCB,
59                          short pair,
60                          short f,
61                          short b);
62 static void drv_initcolor(TERMINAL_CONTROL_BLOCK * TCB,
63                           short color,
64                           short r,
65                           short g,
66                           short b);
67 static void drv_do_color(TERMINAL_CONTROL_BLOCK * TCB,
68                          short old_pair,
69                          short pair,
70                          bool reverse,
71                          int (*outc) (SCREEN *, int));
72 static void drv_initmouse(TERMINAL_CONTROL_BLOCK * TCB);
73 static void drv_setfilter(TERMINAL_CONTROL_BLOCK * TCB);
74 static void drv_hwlabel(TERMINAL_CONTROL_BLOCK * TCB,
75                         int labnum,
76                         char *text);
77 static void drv_hwlabelOnOff(TERMINAL_CONTROL_BLOCK * TCB,
78                              bool OnFlag);
79 static int drv_doupdate(TERMINAL_CONTROL_BLOCK * TCB);
80
81 static int drv_defaultcolors(TERMINAL_CONTROL_BLOCK * TCB,
82                              int fg,
83                              int bg);
84 static int drv_print(TERMINAL_CONTROL_BLOCK * TCB,
85                      char *data,
86                      int len);
87 /*static int _getsize(TERMINAL_CONTROL_BLOCK*,int *, int *);*/
88 static int drv_setsize(TERMINAL_CONTROL_BLOCK * TCB, int l, int c);
89 static void drv_initacs(TERMINAL_CONTROL_BLOCK * TCB, chtype *, chtype *);
90 static void drv_wrap(SCREEN *);
91 static void drv_screen_init(SCREEN *);
92 static int drv_twait(TERMINAL_CONTROL_BLOCK *,
93                      int,
94                      int,
95                      int *EVENTLIST_2nd(_nc_eventlist *));
96 static int drv_read(TERMINAL_CONTROL_BLOCK * TCB, int *buf);
97 static int drv_nap(TERMINAL_CONTROL_BLOCK * TCB GCC_UNUSED, int ms);
98 static int drv_kpad(TERMINAL_CONTROL_BLOCK * TCB, bool);
99 static int drv_keyok(TERMINAL_CONTROL_BLOCK * TCB, int, bool);
100 static bool drv_kyExist(TERMINAL_CONTROL_BLOCK * TCB, int);
101
102 NCURSES_EXPORT_VAR (TERM_DRIVER) _nc_WIN_DRIVER = {
103     FALSE,
104         drv_CanHandle,          /* CanHandle */
105         drv_init,               /* init */
106         drv_release,            /* release */
107         drv_size,               /* size */
108         drv_sgmode,             /* sgmode */
109         drv_conattr,            /* conattr */
110         drv_mvcur,              /* hwcur */
111         drv_mode,               /* mode */
112         drv_rescol,             /* rescol */
113         drv_rescolors,          /* rescolors */
114         drv_setcolor,           /* color */
115         drv_dobeepflash,        /* DoBeepFlash */
116         drv_initpair,           /* initpair */
117         drv_initcolor,          /* initcolor */
118         drv_do_color,           /* docolor */
119         drv_initmouse,          /* initmouse */
120         drv_setfilter,          /* setfilter */
121         drv_hwlabel,            /* hwlabel */
122         drv_hwlabelOnOff,       /* hwlabelOnOff */
123         drv_doupdate,           /* update */
124         drv_defaultcolors,      /* defaultcolors */
125         drv_print,              /* print */
126         drv_size,               /* getsize */
127         drv_setsize,            /* setsize */
128         drv_initacs,            /* initacs */
129         drv_screen_init,        /* scinit */
130         drv_wrap,               /* scexit */
131         drv_twait,              /* twait */
132         drv_read,               /* read */
133         drv_nap,                /* nap */
134         drv_kpad,               /* kpad */
135         drv_keyok,              /* kyOk */
136         drv_kyExist             /* kyExist */
137 };
138
139 #define WINMAGIC NCDRV_MAGIC(NCDRV_WINCONSOLE)
140
141 #define AssertTCB() assert(TCB!=0 && TCB->magic==WINMAGIC)
142 #define SetSP() assert(TCB->csp!=0); sp = TCB->csp
143
144 #define GenMap(vKey,key) MAKELONG(key, vKey)
145
146 static const LONG keylist[] =
147 {
148     GenMap(VK_PRIOR, KEY_PPAGE),
149     GenMap(VK_NEXT, KEY_NPAGE),
150     GenMap(VK_END, KEY_END),
151     GenMap(VK_HOME, KEY_HOME),
152     GenMap(VK_LEFT, KEY_LEFT),
153     GenMap(VK_UP, KEY_UP),
154     GenMap(VK_RIGHT, KEY_RIGHT),
155     GenMap(VK_DOWN, KEY_DOWN),
156     GenMap(VK_DELETE, KEY_DC),
157     GenMap(VK_INSERT, KEY_IC)
158 };
159 #define N_INI ((int)(sizeof(keylist)/sizeof(keylist[0])))
160 #define FKEYS 24
161 #define MAPSIZE (FKEYS + N_INI)
162 #define NUMPAIRS 64
163
164 typedef struct props {
165     CONSOLE_SCREEN_BUFFER_INFO SBI;
166     bool progMode;
167     DWORD map[MAPSIZE];
168     DWORD rmap[MAPSIZE];
169     WORD pairs[NUMPAIRS];
170 } Properties;
171
172 #define PropOf(TCB) ((Properties*)TCB->prop)
173
174 int
175 _nc_mingw_ioctl(int fd GCC_UNUSED,
176                 long int request GCC_UNUSED,
177                 struct termios *arg GCC_UNUSED)
178 {
179     return 0;
180     endwin();
181     fprintf(stderr, "TERMINFO currently not supported on Windows.\n");
182     exit(1);
183 }
184
185 static WORD
186 MapColor(bool fore, int color)
187 {
188     static const int _cmap[] =
189     {0, 4, 2, 6, 1, 5, 3, 7};
190     int a;
191     if (color < 0 || color > 7)
192         a = fore ? 7 : 0;
193     else
194         a = _cmap[color];
195     if (!fore)
196         a = a << 4;
197     return (WORD) a;
198 }
199
200 static WORD
201 MapAttr(TERMINAL_CONTROL_BLOCK * TCB, WORD res, chtype ch)
202 {
203     if (ch & A_COLOR) {
204         int p;
205         SCREEN *sp;
206
207         AssertTCB();
208         SetSP();
209         p = PAIR_NUMBER(ch);
210         if (p > 0 && p < NUMPAIRS && TCB != 0 && sp != 0) {
211             WORD a;
212             a = PropOf(TCB)->pairs[p];
213             res = (res & 0xff00) | a;
214         }
215     }
216
217     if (ch & A_REVERSE)
218         res = ((res & 0xff00) | (((res & 0x07) << 4) | ((res & 0x70) >> 4)));
219
220     if (ch & A_STANDOUT)
221         res = ((res & 0xff00) | (((res & 0x07) << 4) | ((res & 0x70) >> 4))
222                | BACKGROUND_INTENSITY);
223
224     if (ch & A_BOLD)
225         res |= FOREGROUND_INTENSITY;
226
227     if (ch & A_DIM)
228         res |= BACKGROUND_INTENSITY;
229
230     return res;
231 }
232
233 static BOOL
234 con_write(TERMINAL_CONTROL_BLOCK * TCB, int y, int x, chtype *str, int n)
235 {
236     CHAR_INFO ci[n];
237     COORD loc, siz;
238     SMALL_RECT rec;
239     int i;
240     chtype ch;
241     SCREEN *sp;
242
243     AssertTCB();
244
245     if (TCB == 0 || InvalidConsoleHandle(TCB->hdl))
246         return FALSE;
247
248     SetSP();
249
250     for (i = 0; i < n; i++) {
251         ch = str[i];
252         ci[i].Char.AsciiChar = ChCharOf(ch);
253         ci[i].Attributes = MapAttr(TCB,
254                                    PropOf(TCB)->SBI.wAttributes,
255                                    ChAttrOf(ch));
256         if (ChAttrOf(ch) & A_ALTCHARSET) {
257             if (sp->_acs_map)
258                 ci[i].Char.AsciiChar =
259                     ChCharOf(NCURSES_SP_NAME(_nc_acs_char) (sp, ChCharOf(ch)));
260         }
261     }
262
263     loc.X = (short) 0;
264     loc.Y = (short) 0;
265     siz.X = (short) n;
266     siz.Y = 1;
267
268     rec.Left = (short) x;
269     rec.Top = (short) y;
270     rec.Right = (short) (x + n - 1);
271     rec.Bottom = rec.Top;
272
273     return WriteConsoleOutput(TCB->hdl, ci, siz, loc, &rec);
274 }
275
276 #define MARK_NOCHANGE(win,row) \
277                 win->_line[row].firstchar = _NOCHANGE; \
278                 win->_line[row].lastchar  = _NOCHANGE
279
280 static int
281 drv_doupdate(TERMINAL_CONTROL_BLOCK * TCB)
282 {
283     int y, nonempty, n, x0, x1, Width, Height;
284     SCREEN *sp;
285
286     AssertTCB();
287     SetSP();
288
289     Width = screen_columns(sp);
290     Height = screen_lines(sp);
291     nonempty = min(Height, NewScreen(sp)->_maxy + 1);
292
293     if ((CurScreen(sp)->_clear || NewScreen(sp)->_clear)) {
294         int x;
295         chtype empty[Width];
296
297         for (x = 0; x < Width; x++)
298             empty[x] = ' ';
299
300         for (y = 0; y < nonempty; y++) {
301             con_write(TCB, y, 0, empty, Width);
302             memcpy(empty,
303                    CurScreen(sp)->_line[y].text,
304                    Width * sizeof(chtype));
305         }
306         CurScreen(sp)->_clear = FALSE;
307         NewScreen(sp)->_clear = FALSE;
308         touchwin(NewScreen(sp));
309     }
310
311     for (y = 0; y < nonempty; y++) {
312         x0 = NewScreen(sp)->_line[y].firstchar;
313         if (x0 != _NOCHANGE) {
314             x1 = NewScreen(sp)->_line[y].lastchar;
315             n = x1 - x0 + 1;
316             if (n > 0) {
317                 memcpy(CurScreen(sp)->_line[y].text + x0,
318                        NewScreen(sp)->_line[y].text + x0,
319                        n * sizeof(chtype));
320                 con_write(TCB,
321                           y,
322                           x0,
323                           ((chtype *) CurScreen(sp)->_line[y].text) + x0, n);
324
325                 /* mark line changed successfully */
326                 if (y <= NewScreen(sp)->_maxy) {
327                     MARK_NOCHANGE(NewScreen(sp), y);
328                 }
329                 if (y <= CurScreen(sp)->_maxy) {
330                     MARK_NOCHANGE(CurScreen(sp), y);
331                 }
332             }
333         }
334     }
335
336     /* put everything back in sync */
337     for (y = nonempty; y <= NewScreen(sp)->_maxy; y++) {
338         MARK_NOCHANGE(NewScreen(sp), y);
339     }
340     for (y = nonempty; y <= CurScreen(sp)->_maxy; y++) {
341         MARK_NOCHANGE(CurScreen(sp), y);
342     }
343
344     if (!NewScreen(sp)->_leaveok) {
345         CurScreen(sp)->_curx = NewScreen(sp)->_curx;
346         CurScreen(sp)->_cury = NewScreen(sp)->_cury;
347
348         TCB->drv->hwcur(TCB, 0, 0, CurScreen(sp)->_cury, CurScreen(sp)->_curx);
349     }
350     SetConsoleActiveScreenBuffer(TCB->hdl);
351     return OK;
352 }
353
354 static bool
355 drv_CanHandle(TERMINAL_CONTROL_BLOCK * TCB,
356               const char *tname,
357               int *errret GCC_UNUSED)
358 {
359     assert(TCB != 0);
360     assert(tname != 0);
361     TCB->magic = WINMAGIC;
362     if (*tname == 0 || *tname == 0 || strcmp(tname, "unknown") == 0) {
363         return TRUE;
364     } else
365         return FALSE;
366 }
367
368 static int
369 drv_dobeepflash(TERMINAL_CONTROL_BLOCK * TCB,
370                 bool beepFlag GCC_UNUSED)
371 {
372     SCREEN *sp;
373     int res = ERR;
374
375     AssertTCB();
376     SetSP();
377
378     return res;
379 }
380
381 static int
382 drv_print(TERMINAL_CONTROL_BLOCK * TCB,
383           char *data GCC_UNUSED,
384           int len GCC_UNUSED)
385 {
386     SCREEN *sp;
387
388     AssertTCB();
389     SetSP();
390
391     return ERR;
392 }
393
394 static int
395 drv_defaultcolors(TERMINAL_CONTROL_BLOCK * TCB,
396                   int fg GCC_UNUSED,
397                   int bg GCC_UNUSED)
398 {
399     SCREEN *sp;
400     int code = ERR;
401
402     AssertTCB();
403     SetSP();
404
405     return (code);
406 }
407
408 static void
409 drv_setcolor(TERMINAL_CONTROL_BLOCK * TCB,
410              bool fore,
411              int color,
412              int (*outc) (SCREEN *, int) GCC_UNUSED)
413 {
414     AssertTCB();
415
416     if (TCB && !InvalidConsoleHandle(TCB->hdl)) {
417         WORD a = MapColor(fore, color);
418         a = ((PropOf(TCB)->SBI.wAttributes) & (fore ? 0xfff8 : 0xff8f)) | a;
419         SetConsoleTextAttribute(TCB->hdl, a);
420         GetConsoleScreenBufferInfo(TCB->hdl, &(PropOf(TCB)->SBI));
421     }
422 }
423
424 static bool
425 drv_rescol(TERMINAL_CONTROL_BLOCK * TCB)
426 {
427     bool res = FALSE;
428
429     AssertTCB();
430     if (TCB && !InvalidConsoleHandle(TCB->hdl)) {
431         WORD a = FOREGROUND_BLUE | FOREGROUND_RED | FOREGROUND_GREEN;
432         SetConsoleTextAttribute(TCB->hdl, a);
433         GetConsoleScreenBufferInfo(TCB->hdl, &(PropOf(TCB)->SBI));
434         res = TRUE;
435     }
436     return res;
437 }
438
439 static bool
440 drv_rescolors(TERMINAL_CONTROL_BLOCK * TCB)
441 {
442     int result = FALSE;
443     SCREEN *sp;
444
445     AssertTCB();
446     SetSP();
447
448     return result;
449 }
450
451 static int
452 drv_size(TERMINAL_CONTROL_BLOCK * TCB, int *Lines, int *Cols)
453 {
454     AssertTCB();
455
456     if (TCB == NULL || Lines == NULL || Cols == NULL || InvalidConsoleHandle(TCB->hdl))
457         return ERR;
458
459     *Lines = (int) (PropOf(TCB)->SBI.dwSize.Y);
460     *Cols = (int) (PropOf(TCB)->SBI.dwSize.X);
461     return OK;
462 }
463
464 static int
465 drv_setsize(TERMINAL_CONTROL_BLOCK * TCB GCC_UNUSED,
466             int l GCC_UNUSED,
467             int c GCC_UNUSED)
468 {
469     AssertTCB();
470     return ERR;
471 }
472
473 static int
474 drv_mode(TERMINAL_CONTROL_BLOCK * TCB, bool progFlag, bool defFlag)
475 {
476     SCREEN *sp;
477     TERMINAL *_term = (TERMINAL *) TCB;
478     int code = ERR;
479
480     AssertTCB();
481     sp = TCB->csp;
482
483     PropOf(TCB)->progMode = progFlag;
484     SetConsoleActiveScreenBuffer(progFlag ? TCB->hdl : TCB->out);
485
486     if (progFlag) /* prog mode */  {
487         if (defFlag) {
488             if ((drv_sgmode(TCB, FALSE, &(_term->Nttyb)) == OK)) {
489                 _term->Nttyb.c_oflag &= ~OFLAGS_TABS;
490                 code = OK;
491             }
492         } else {
493             /* reset_prog_mode */
494             if (drv_sgmode(TCB, TRUE, &(_term->Nttyb)) == OK) {
495                 if (sp) {
496                     if (sp->_keypad_on)
497                         _nc_keypad(sp, TRUE);
498                     NC_BUFFERED(sp, TRUE);
499                 }
500                 code = OK;
501             }
502         }
503     } else {                    /* shell mode */
504         if (defFlag) {
505             /* def_shell_mode */
506             if (drv_sgmode(TCB, FALSE, &(_term->Ottyb)) == OK) {
507                 code = OK;
508             }
509         } else {
510             /* reset_shell_mode */
511             if (sp) {
512                 _nc_keypad(sp, FALSE);
513                 NCURSES_SP_NAME(_nc_flush) (sp);
514                 NC_BUFFERED(sp, FALSE);
515             }
516             code = drv_sgmode(TCB, TRUE, &(_term->Ottyb));
517         }
518     }
519
520     return (code);
521 }
522
523 static void
524 drv_screen_init(SCREEN *sp GCC_UNUSED)
525 {
526 }
527
528 static void
529 drv_wrap(SCREEN *sp GCC_UNUSED)
530 {
531 }
532
533 static int
534 rkeycompare(const void *el1, const void *el2)
535 {
536     WORD key1 = (LOWORD((*((const LONG *) el1)))) & 0x7fff;
537     WORD key2 = (LOWORD((*((const LONG *) el2)))) & 0x7fff;
538
539     return ((key1 < key2) ? -1 : ((key1 == key2) ? 0 : 1));
540 }
541
542 static int
543 keycompare(const void *el1, const void *el2)
544 {
545     WORD key1 = HIWORD((*((const LONG *) el1)));
546     WORD key2 = HIWORD((*((const LONG *) el2)));
547
548     return ((key1 < key2) ? -1 : ((key1 == key2) ? 0 : 1));
549 }
550
551 static int
552 MapKey(TERMINAL_CONTROL_BLOCK * TCB, WORD vKey)
553 {
554     WORD nKey = 0;
555     void *res;
556     LONG key = GenMap(vKey, 0);
557     int code = -1;
558
559     AssertTCB();
560
561     res = bsearch(&key,
562                   PropOf(TCB)->map,
563                   (size_t) (N_INI + FKEYS),
564                   sizeof(keylist[0]),
565                   keycompare);
566     if (res) {
567         key = *((LONG *) res);
568         nKey = LOWORD(key);
569         code = (int) (nKey & 0x7fff);
570         if (nKey & 0x8000)
571             code = -code;
572     }
573     return code;
574 }
575
576 static void
577 drv_release(TERMINAL_CONTROL_BLOCK * TCB)
578 {
579     AssertTCB();
580     if (TCB->prop)
581         free(TCB->prop);
582 }
583
584 static void
585 drv_init(TERMINAL_CONTROL_BLOCK * TCB)
586 {
587     AssertTCB();
588
589     if (TCB) {
590         BOOL b = AllocConsole();
591         WORD a;
592         int i;
593
594         if (!b)
595             b = AttachConsole(ATTACH_PARENT_PROCESS);
596
597         TCB->inp = GetStdHandle(STD_INPUT_HANDLE);
598         TCB->out = GetStdHandle(STD_OUTPUT_HANDLE);
599
600         if (getenv("NCGDB"))
601             TCB->hdl = TCB->out;
602         else
603             TCB->hdl = CreateConsoleScreenBuffer(GENERIC_READ | GENERIC_WRITE,
604                                                  0,
605                                                  NULL,
606                                                  CONSOLE_TEXTMODE_BUFFER,
607                                                  NULL);
608
609         if (!InvalidConsoleHandle(TCB->hdl)) {
610             TCB->prop = typeCalloc(Properties, 1);
611             GetConsoleScreenBufferInfo(TCB->hdl, &(PropOf(TCB)->SBI));
612         }
613
614         TCB->info.initcolor = TRUE;
615         TCB->info.canchange = FALSE;
616         TCB->info.hascolor = TRUE;
617         TCB->info.caninit = TRUE;
618
619         TCB->info.maxpairs = NUMPAIRS;
620         TCB->info.maxcolors = 8;
621         TCB->info.numlabels = 0;
622         TCB->info.labelwidth = 0;
623         TCB->info.labelheight = 0;
624         TCB->info.nocolorvideo = 1;
625         TCB->info.tabsize = 8;
626
627         TCB->info.defaultPalette = _nc_cga_palette;
628
629         for (i = 0; i < (N_INI + FKEYS); i++) {
630             if (i < N_INI)
631                 PropOf(TCB)->rmap[i] = PropOf(TCB)->map[i] = keylist[i];
632             else
633                 PropOf(TCB)->rmap[i] = PropOf(TCB)->map[i] =
634                     GenMap((VK_F1 + (i - N_INI)), (KEY_F(1) + (i - N_INI)));
635         }
636         qsort(PropOf(TCB)->map,
637               (size_t) (MAPSIZE),
638               sizeof(keylist[0]),
639               keycompare);
640         qsort(PropOf(TCB)->rmap,
641               (size_t) (MAPSIZE),
642               sizeof(keylist[0]),
643               rkeycompare);
644
645         a = MapColor(true, COLOR_WHITE) | MapColor(false, COLOR_BLACK);
646         for (i = 0; i < NUMPAIRS; i++)
647             PropOf(TCB)->pairs[i] = a;
648     }
649 }
650
651 static void
652 drv_initpair(TERMINAL_CONTROL_BLOCK * TCB,
653              short pair,
654              short f,
655              short b)
656 {
657     SCREEN *sp;
658
659     AssertTCB();
660     SetSP();
661
662     if ((pair > 0) && (pair < NUMPAIRS) && (f >= 0) && (f < 8)
663         && (b >= 0) && (b < 8)) {
664         PropOf(TCB)->pairs[pair] = MapColor(true, f) | MapColor(false, b);
665     }
666 }
667
668 static void
669 drv_initcolor(TERMINAL_CONTROL_BLOCK * TCB,
670               short color GCC_UNUSED,
671               short r GCC_UNUSED,
672               short g GCC_UNUSED,
673               short b GCC_UNUSED)
674 {
675     SCREEN *sp;
676
677     AssertTCB();
678     SetSP();
679 }
680
681 static void
682 drv_do_color(TERMINAL_CONTROL_BLOCK * TCB,
683              short old_pair GCC_UNUSED,
684              short pair GCC_UNUSED,
685              bool reverse GCC_UNUSED,
686              int (*outc) (SCREEN *, int) GCC_UNUSED
687 )
688 {
689     SCREEN *sp;
690
691     AssertTCB();
692     SetSP();
693 }
694
695 static void
696 drv_initmouse(TERMINAL_CONTROL_BLOCK * TCB)
697 {
698     SCREEN *sp;
699
700     AssertTCB();
701     SetSP();
702 }
703
704 static int
705 drv_mvcur(TERMINAL_CONTROL_BLOCK * TCB,
706           int yold GCC_UNUSED, int xold GCC_UNUSED,
707           int y, int x)
708 {
709     int ret = ERR;
710     if (TCB && !InvalidConsoleHandle(TCB->hdl)) {
711         COORD loc;
712         loc.X = (short) x;
713         loc.Y = (short) y;
714         SetConsoleCursorPosition(TCB->hdl, loc);
715         ret = OK;
716     }
717     return ret;
718 }
719
720 static void
721 drv_hwlabel(TERMINAL_CONTROL_BLOCK * TCB,
722             int labnum GCC_UNUSED,
723             char *text GCC_UNUSED)
724 {
725     SCREEN *sp;
726
727     AssertTCB();
728     SetSP();
729 }
730
731 static void
732 drv_hwlabelOnOff(TERMINAL_CONTROL_BLOCK * TCB,
733                  bool OnFlag GCC_UNUSED)
734 {
735     SCREEN *sp;
736
737     AssertTCB();
738     SetSP();
739 }
740
741 static chtype
742 drv_conattr(TERMINAL_CONTROL_BLOCK * TCB GCC_UNUSED)
743 {
744     chtype res = A_NORMAL;
745     res |= (A_BOLD | A_DIM | A_REVERSE | A_STANDOUT | A_COLOR);
746     return res;
747 }
748
749 static void
750 drv_setfilter(TERMINAL_CONTROL_BLOCK * TCB)
751 {
752     SCREEN *sp;
753
754     AssertTCB();
755     SetSP();
756 }
757
758 static int
759 drv_sgmode(TERMINAL_CONTROL_BLOCK * TCB, bool setFlag, TTY * buf)
760 {
761     DWORD dwFlag = 0;
762     tcflag_t iflag;
763     tcflag_t lflag;
764
765     AssertTCB();
766
767     if (TCB == 0 || buf == NULL)
768         return ERR;
769
770     if (setFlag) {
771         iflag = buf->c_iflag;
772         lflag = buf->c_lflag;
773
774         GetConsoleMode(TCB->inp, &dwFlag);
775
776         if (lflag & ICANON)
777             dwFlag |= ENABLE_LINE_INPUT;
778         else
779             dwFlag &= ~ENABLE_LINE_INPUT;
780
781         if (lflag & ECHO)
782             dwFlag |= ENABLE_ECHO_INPUT;
783         else
784             dwFlag &= ~ENABLE_ECHO_INPUT;
785
786         if (iflag & BRKINT)
787             dwFlag |= ENABLE_PROCESSED_INPUT;
788         else
789             dwFlag &= ~ENABLE_PROCESSED_INPUT;
790
791         /* we disable that for now to focus on keyboard. */
792         dwFlag &= ~ENABLE_MOUSE_INPUT;
793
794         buf->c_iflag = iflag;
795         buf->c_lflag = lflag;
796         SetConsoleMode(TCB->inp, dwFlag);
797         TCB->term.Nttyb = *buf;
798     } else {
799         iflag = TCB->term.Nttyb.c_iflag;
800         lflag = TCB->term.Nttyb.c_lflag;
801         GetConsoleMode(TCB->inp, &dwFlag);
802
803         if (dwFlag & ENABLE_LINE_INPUT)
804             lflag |= ICANON;
805         else
806             lflag &= ~ICANON;
807
808         if (dwFlag & ENABLE_ECHO_INPUT)
809             lflag |= ECHO;
810         else
811             lflag &= ~ECHO;
812
813         if (dwFlag & ENABLE_PROCESSED_INPUT)
814             iflag |= BRKINT;
815         else
816             iflag &= ~BRKINT;
817
818         TCB->term.Nttyb.c_iflag = iflag;
819         TCB->term.Nttyb.c_lflag = lflag;
820
821         *buf = TCB->term.Nttyb;
822     }
823     return OK;
824 }
825
826 static void
827 drv_initacs(TERMINAL_CONTROL_BLOCK * TCB,
828             chtype *real_map GCC_UNUSED,
829             chtype *fake_map GCC_UNUSED)
830 {
831     SCREEN *sp;
832     AssertTCB();
833     SetSP();
834 }
835
836 static ULONGLONG
837 tdiff(FILETIME fstart, FILETIME fend)
838 {
839     ULARGE_INTEGER ustart;
840     ULARGE_INTEGER uend;
841     ULONGLONG diff;
842
843     ustart.LowPart = fstart.dwLowDateTime;
844     ustart.HighPart = fstart.dwHighDateTime;
845     uend.LowPart = fend.dwLowDateTime;
846     uend.HighPart = fend.dwHighDateTime;
847
848     diff = (uend.QuadPart - ustart.QuadPart) / 10000;
849     return diff;
850 }
851
852 static int
853 Adjust(int milliseconds, int diff)
854 {
855     if (milliseconds == INFINITY)
856         return milliseconds;
857     milliseconds -= diff;
858     if (milliseconds < 0)
859         milliseconds = 0;
860     return milliseconds;
861 }
862
863 static int
864 drv_twait(TERMINAL_CONTROL_BLOCK * TCB,
865           int mode,
866           int milliseconds,
867           int *timeleft
868           EVENTLIST_2nd(_nc_eventlist * evl))
869 {
870     SCREEN *sp;
871     INPUT_RECORD inp;
872     BOOL b;
873     DWORD nRead = 0, rc = -1;
874     int code = 0;
875     FILETIME fstart;
876     FILETIME fend;
877     int diff;
878     bool isImmed = (milliseconds == 0);
879
880 #define CONSUME() ReadConsoleInput(TCB->inp,&inp,1,&nRead)
881
882     AssertTCB();
883     SetSP();
884
885     if (milliseconds < 0)
886         milliseconds = INFINITY;
887
888     memset(&inp, 0, sizeof(inp));
889
890     while (true) {
891         GetSystemTimeAsFileTime(&fstart);
892         rc = WaitForSingleObject(TCB->inp, milliseconds);
893         GetSystemTimeAsFileTime(&fend);
894         diff = (int) tdiff(fstart, fend);
895         milliseconds = Adjust(milliseconds, diff);
896
897         if (!isImmed && milliseconds == 0)
898             break;
899
900         if (rc == WAIT_OBJECT_0) {
901             if (mode) {
902                 b = GetNumberOfConsoleInputEvents(TCB->inp, &nRead);
903                 if (b && nRead > 0) {
904                     b = PeekConsoleInput(TCB->inp, &inp, 1, &nRead);
905                     if (b && nRead > 0) {
906                         switch (inp.EventType) {
907                         case KEY_EVENT:
908                             if (mode & TW_INPUT) {
909                                 WORD vk = inp.Event.KeyEvent.wVirtualKeyCode;
910                                 char ch = inp.Event.KeyEvent.uChar.AsciiChar;
911
912                                 if (inp.Event.KeyEvent.bKeyDown) {
913                                     if (0 == ch) {
914                                         int nKey = MapKey(TCB, vk);
915                                         if ((nKey < 0) || FALSE == sp->_keypad_on) {
916                                             CONSUME();
917                                             continue;
918                                         }
919                                     }
920                                     code = TW_INPUT;
921                                     goto end;
922                                 } else {
923                                     CONSUME();
924                                 }
925                             }
926                             continue;
927                         case MOUSE_EVENT:
928                             if (0 && mode & TW_MOUSE) {
929                                 code = TW_MOUSE;
930                                 goto end;
931                             } else
932                                 continue;
933                         default:
934                             SetConsoleActiveScreenBuffer(!PropOf(TCB)->progMode ?
935                                                          TCB->hdl : TCB->out);
936                             continue;
937                         }
938                     }
939                 }
940             }
941             continue;
942         } else {
943             if (rc != WAIT_TIMEOUT) {
944                 code = -1;
945                 break;
946             } else {
947                 code = 0;
948                 break;
949             }
950         }
951     }
952   end:
953     if (timeleft)
954         *timeleft = milliseconds;
955
956     return code;
957 }
958
959 static int
960 drv_read(TERMINAL_CONTROL_BLOCK * TCB, int *buf)
961 {
962     SCREEN *sp;
963     int n = 1;
964     INPUT_RECORD inp;
965     BOOL b;
966     DWORD nRead;
967     WORD vk;
968     WORD sc;
969
970     AssertTCB();
971     assert(buf);
972     SetSP();
973
974     memset(&inp, 0, sizeof(inp));
975
976     while ((b = ReadConsoleInput(TCB->inp, &inp, 1, &nRead))) {
977         if (b && nRead > 0) {
978             if (inp.EventType == KEY_EVENT) {
979                 if (!inp.Event.KeyEvent.bKeyDown)
980                     continue;
981                 *buf = (int) inp.Event.KeyEvent.uChar.AsciiChar;
982                 vk = inp.Event.KeyEvent.wVirtualKeyCode;
983                 sc = inp.Event.KeyEvent.wVirtualScanCode;
984                 if (*buf == 0) {
985                     if (sp->_keypad_on) {
986                         *buf = MapKey(TCB, vk);
987                         if (0 > (*buf))
988                             continue;
989                         else
990                             break;
991                     } else
992                         continue;
993                 } else {        /* *buf != 0 */
994                     break;
995                 }
996             } else if (0 && inp.EventType == MOUSE_EVENT) {
997                 *buf = KEY_MOUSE;
998                 break;
999             }
1000             continue;
1001         }
1002     }
1003     return n;
1004 }
1005
1006 static int
1007 drv_nap(TERMINAL_CONTROL_BLOCK * TCB GCC_UNUSED, int ms)
1008 {
1009     Sleep(ms);
1010     return OK;
1011 }
1012
1013 static bool
1014 drv_kyExist(TERMINAL_CONTROL_BLOCK * TCB, int keycode)
1015 {
1016     SCREEN *sp;
1017     WORD nKey;
1018     void *res;
1019     bool found = FALSE;
1020     LONG key = GenMap(0, (WORD) keycode);
1021
1022     AssertTCB();
1023     SetSP();
1024
1025     AssertTCB();
1026
1027     res = bsearch(&key,
1028                   PropOf(TCB)->rmap,
1029                   (size_t) (N_INI + FKEYS),
1030                   sizeof(keylist[0]),
1031                   rkeycompare);
1032     if (res) {
1033         key = *((LONG *) res);
1034         nKey = LOWORD(key);
1035         if (!(nKey & 0x8000))
1036             found = TRUE;
1037     }
1038     return found;
1039 }
1040
1041 static int
1042 drv_kpad(TERMINAL_CONTROL_BLOCK * TCB, bool flag GCC_UNUSED)
1043 {
1044     SCREEN *sp;
1045     int code = ERR;
1046
1047     AssertTCB();
1048     sp = TCB->csp;
1049
1050     if (sp) {
1051         code = OK;
1052     }
1053     return code;
1054 }
1055
1056 static int
1057 drv_keyok(TERMINAL_CONTROL_BLOCK * TCB, int keycode, bool flag)
1058 {
1059     int code = ERR;
1060     SCREEN *sp;
1061     WORD nKey;
1062     WORD vKey;
1063     void *res;
1064     LONG key = GenMap(0, (WORD) keycode);
1065
1066     AssertTCB();
1067     SetSP();
1068
1069     if (sp) {
1070         res = bsearch(&key,
1071                       PropOf(TCB)->rmap,
1072                       (size_t) (N_INI + FKEYS),
1073                       sizeof(keylist[0]),
1074                       rkeycompare);
1075         if (res) {
1076             key = *((LONG *) res);
1077             vKey = HIWORD(key);
1078             nKey = (LOWORD(key)) & 0x7fff;
1079             if (!flag)
1080                 nKey |= 0x8000;
1081             *(LONG *) res = GenMap(vKey, nKey);
1082         }
1083     }
1084     return code;
1085 }