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