1 /****************************************************************************
2 * Copyright (c) 1998-2013,2014 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 * TODO - GetMousePos(POINT * result) from ntconio.c
35 * TODO - implement nodelay
36 * TODO - when $NCGDB is set, implement non-buffered output, like PDCurses
37 */
38
39 #include <curses.priv.h>
40 #define CUR my_term.type.
41
42 MODULE_ID("$Id: win_driver.c,v 1.24 2014/02/23 01:23:29 tom Exp $")
43
44 #define WINMAGIC NCDRV_MAGIC(NCDRV_WINCONSOLE)
45
46 #define EXP_OPTIMIZE 0
47
48 #define okConsoleHandle(TCB) (TCB != 0 && !InvalidConsoleHandle(TCB->hdl))
49
50 #define AssertTCB() assert(TCB != 0 && (TCB->magic == WINMAGIC))
51 #define SetSP() assert(TCB->csp != 0); sp = TCB->csp; (void) sp
52
53 #define GenMap(vKey,key) MAKELONG(key, vKey)
54
55 #define AdjustY(p) ((p)->buffered ? 0 : (int) (p)->SBI.srWindow.Top)
56
57 static const LONG keylist[] =
58 {
59 GenMap(VK_PRIOR, KEY_PPAGE),
60 GenMap(VK_NEXT, KEY_NPAGE),
61 GenMap(VK_END, KEY_END),
62 GenMap(VK_HOME, KEY_HOME),
63 GenMap(VK_LEFT, KEY_LEFT),
64 GenMap(VK_UP, KEY_UP),
65 GenMap(VK_RIGHT, KEY_RIGHT),
66 GenMap(VK_DOWN, KEY_DOWN),
67 GenMap(VK_DELETE, KEY_DC),
68 GenMap(VK_INSERT, KEY_IC)
69 };
70 #define N_INI ((int)(sizeof(keylist)/sizeof(keylist[0])))
71 #define FKEYS 24
72 #define MAPSIZE (FKEYS + N_INI)
73 #define NUMPAIRS 64
74
75 typedef struct props {
76 CONSOLE_SCREEN_BUFFER_INFO SBI;
77 bool progMode;
78 TERM_HANDLE lastOut;
79 DWORD map[MAPSIZE];
80 DWORD rmap[MAPSIZE];
81 WORD pairs[NUMPAIRS];
82 bool buffered;
83 COORD origin;
84 CHAR_INFO *save_screen;
85 } Properties;
86
87 #define PropOf(TCB) ((Properties*)TCB->prop)
88
89 int
_nc_mingw_ioctl(int fd GCC_UNUSED,long int request GCC_UNUSED,struct termios * arg GCC_UNUSED)90 _nc_mingw_ioctl(int fd GCC_UNUSED,
91 long int request GCC_UNUSED,
92 struct termios *arg GCC_UNUSED)
93 {
94 return 0;
95 endwin();
96 fprintf(stderr, "TERMINFO currently not supported on Windows.\n");
97 exit(1);
98 }
99
100 static WORD
MapColor(bool fore,int color)101 MapColor(bool fore, int color)
102 {
103 static const int _cmap[] =
104 {0, 4, 2, 6, 1, 5, 3, 7};
105 int a;
106 if (color < 0 || color > 7)
107 a = fore ? 7 : 0;
108 else
109 a = _cmap[color];
110 if (!fore)
111 a = a << 4;
112 return (WORD) a;
113 }
114
115 static WORD
MapAttr(TERMINAL_CONTROL_BLOCK * TCB,WORD res,attr_t ch)116 MapAttr(TERMINAL_CONTROL_BLOCK * TCB, WORD res, attr_t ch)
117 {
118 if (ch & A_COLOR) {
119 int p;
120 SCREEN *sp;
121
122 AssertTCB();
123 SetSP();
124 p = PairNumber(ch);
125 if (p > 0 && p < NUMPAIRS && TCB != 0 && sp != 0) {
126 WORD a;
127 a = PropOf(TCB)->pairs[p];
128 res = (res & 0xff00) | a;
129 }
130 }
131
132 if (ch & A_REVERSE)
133 res = ((res & 0xff00) | (((res & 0x07) << 4) | ((res & 0x70) >> 4)));
134
135 if (ch & A_STANDOUT)
136 res = ((res & 0xff00) | (((res & 0x07) << 4) | ((res & 0x70) >> 4))
137 | BACKGROUND_INTENSITY);
138
139 if (ch & A_BOLD)
140 res |= FOREGROUND_INTENSITY;
141
142 if (ch & A_DIM)
143 res |= BACKGROUND_INTENSITY;
144
145 return res;
146 }
147
148 #if USE_WIDEC_SUPPORT
149 /*
150 * TODO: support surrogate pairs
151 * TODO: support combining characters
152 * TODO: support acsc
153 * TODO: check wcwidth of base character, fill if needed for double-width
154 * TODO: _nc_wacs should be part of sp.
155 */
156 static BOOL
con_write16(TERMINAL_CONTROL_BLOCK * TCB,int y,int x,cchar_t * str,int limit)157 con_write16(TERMINAL_CONTROL_BLOCK * TCB, int y, int x, cchar_t *str, int limit)
158 {
159 int actual = 0;
160 CHAR_INFO ci[limit];
161 COORD loc, siz;
162 SMALL_RECT rec;
163 int i;
164 cchar_t ch;
165 SCREEN *sp;
166 Properties *p = PropOf(TCB);
167
168 AssertTCB();
169
170 SetSP();
171
172 for (i = actual = 0; i < limit; i++) {
173 ch = str[i];
174 if (isWidecExt(ch))
175 continue;
176 ci[actual].Char.UnicodeChar = CharOf(ch);
177 ci[actual].Attributes = MapAttr(TCB,
178 PropOf(TCB)->SBI.wAttributes,
179 AttrOf(ch));
180 if (AttrOf(ch) & A_ALTCHARSET) {
181 if (_nc_wacs) {
182 int which = CharOf(ch);
183 if (which > 0
184 && which < ACS_LEN
185 && CharOf(_nc_wacs[which]) != 0) {
186 ci[actual].Char.UnicodeChar = CharOf(_nc_wacs[which]);
187 } else {
188 ci[actual].Char.UnicodeChar = ' ';
189 }
190 }
191 }
192 ++actual;
193 }
194
195 loc.X = (short) 0;
196 loc.Y = (short) 0;
197 siz.X = (short) actual;
198 siz.Y = 1;
199
200 rec.Left = (short) x;
201 rec.Top = (SHORT) (y + AdjustY(p));
202 rec.Right = (short) (x + limit - 1);
203 rec.Bottom = rec.Top;
204
205 return WriteConsoleOutputW(TCB->hdl, ci, siz, loc, &rec);
206 }
207 #define con_write(tcb, y, x, str, n) con_write16(tcb, y, x, str, n)
208 #else
209 static BOOL
con_write8(TERMINAL_CONTROL_BLOCK * TCB,int y,int x,chtype * str,int n)210 con_write8(TERMINAL_CONTROL_BLOCK * TCB, int y, int x, chtype *str, int n)
211 {
212 CHAR_INFO ci[n];
213 COORD loc, siz;
214 SMALL_RECT rec;
215 int i;
216 chtype ch;
217 SCREEN *sp;
218
219 AssertTCB();
220
221 SetSP();
222
223 for (i = 0; i < n; i++) {
224 ch = str[i];
225 ci[i].Char.AsciiChar = ChCharOf(ch);
226 ci[i].Attributes = MapAttr(TCB,
227 PropOf(TCB)->SBI.wAttributes,
228 ChAttrOf(ch));
229 if (ChAttrOf(ch) & A_ALTCHARSET) {
230 if (sp->_acs_map)
231 ci[i].Char.AsciiChar =
232 ChCharOf(NCURSES_SP_NAME(_nc_acs_char) (sp, ChCharOf(ch)));
233 }
234 }
235
236 loc.X = (short) 0;
237 loc.Y = (short) 0;
238 siz.X = (short) n;
239 siz.Y = 1;
240
241 rec.Left = (short) x;
242 rec.Top = (short) y;
243 rec.Right = (short) (x + n - 1);
244 rec.Bottom = rec.Top;
245
246 return WriteConsoleOutput(TCB->hdl, ci, siz, loc, &rec);
247 }
248 #define con_write(tcb, y, x, str, n) con_write8(tcb, y, x, str, n)
249 #endif
250
251 #if EXP_OPTIMIZE
252 /*
253 * Comparing new/current screens, determine the last column-index for a change
254 * beginning on the given row,col position. Unlike a serial terminal, there is
255 * no cost for "moving" the "cursor" on the line as we update it.
256 */
257 static int
find_end_of_change(SCREEN * sp,int row,int col)258 find_end_of_change(SCREEN *sp, int row, int col)
259 {
260 int result = col;
261 struct ldat *curdat = CurScreen(sp)->_line + row;
262 struct ldat *newdat = NewScreen(sp)->_line + row;
263
264 while (col <= newdat->lastchar) {
265 #if USE_WIDEC_SUPPORT
266 if (isWidecExt(curdat->text[col]) || isWidecExt(newdat->text[col])) {
267 result = col;
268 } else if (memcmp(&curdat->text[col],
269 &newdat->text[col],
270 sizeof(curdat->text[0]))) {
271 result = col;
272 } else {
273 break;
274 }
275 #else
276 if (curdat->text[col] != newdat->text[col]) {
277 result = col;
278 } else {
279 break;
280 }
281 #endif
282 ++col;
283 }
284 return result;
285 }
286
287 /*
288 * Given a row,col position at the end of a change-chunk, look for the
289 * beginning of the next change-chunk.
290 */
291 static int
find_next_change(SCREEN * sp,int row,int col)292 find_next_change(SCREEN *sp, int row, int col)
293 {
294 struct ldat *curdat = CurScreen(sp)->_line + row;
295 struct ldat *newdat = NewScreen(sp)->_line + row;
296 int result = newdat->lastchar + 1;
297
298 while (++col <= newdat->lastchar) {
299 #if USE_WIDEC_SUPPORT
300 if (isWidecExt(curdat->text[col]) != isWidecExt(newdat->text[col])) {
301 result = col;
302 break;
303 } else if (memcmp(&curdat->text[col],
304 &newdat->text[col],
305 sizeof(curdat->text[0]))) {
306 result = col;
307 break;
308 }
309 #else
310 if (curdat->text[col] != newdat->text[col]) {
311 result = col;
312 break;
313 }
314 #endif
315 }
316 return result;
317 }
318
319 #define EndChange(first) \
320 find_end_of_change(sp, y, first)
321 #define NextChange(last) \
322 find_next_change(sp, y, last)
323
324 #endif /* EXP_OPTIMIZE */
325
326 #define MARK_NOCHANGE(win,row) \
327 win->_line[row].firstchar = _NOCHANGE; \
328 win->_line[row].lastchar = _NOCHANGE
329
330 static void
selectActiveHandle(TERMINAL_CONTROL_BLOCK * TCB)331 selectActiveHandle(TERMINAL_CONTROL_BLOCK * TCB)
332 {
333 if (PropOf(TCB)->lastOut != TCB->hdl) {
334 PropOf(TCB)->lastOut = TCB->hdl;
335 SetConsoleActiveScreenBuffer(PropOf(TCB)->lastOut);
336 }
337 }
338
339 static int
drv_doupdate(TERMINAL_CONTROL_BLOCK * TCB)340 drv_doupdate(TERMINAL_CONTROL_BLOCK * TCB)
341 {
342 int result = ERR;
343 int y, nonempty, n, x0, x1, Width, Height;
344 SCREEN *sp;
345
346 AssertTCB();
347 SetSP();
348
349 T((T_CALLED("win32con::drv_doupdate(%p)"), TCB));
350 if (okConsoleHandle(TCB)) {
351
352 Width = screen_columns(sp);
353 Height = screen_lines(sp);
354 nonempty = min(Height, NewScreen(sp)->_maxy + 1);
355
356 if ((CurScreen(sp)->_clear || NewScreen(sp)->_clear)) {
357 int x;
358 #if USE_WIDEC_SUPPORT
359 cchar_t empty[Width];
360 wchar_t blank[2] =
361 {
362 L' ', L'\0'
363 };
364
365 for (x = 0; x < Width; x++)
366 setcchar(&empty[x], blank, 0, 0, 0);
367 #else
368 chtype empty[Width];
369
370 for (x = 0; x < Width; x++)
371 empty[x] = ' ';
372 #endif
373
374 for (y = 0; y < nonempty; y++) {
375 con_write(TCB, y, 0, empty, Width);
376 memcpy(empty,
377 CurScreen(sp)->_line[y].text,
378 (size_t) Width * sizeof(empty[0]));
379 }
380 CurScreen(sp)->_clear = FALSE;
381 NewScreen(sp)->_clear = FALSE;
382 touchwin(NewScreen(sp));
383 }
384
385 for (y = 0; y < nonempty; y++) {
386 x0 = NewScreen(sp)->_line[y].firstchar;
387 if (x0 != _NOCHANGE) {
388 #if EXP_OPTIMIZE
389 int x2;
390 int limit = NewScreen(sp)->_line[y].lastchar;
391 while ((x1 = EndChange(x0)) <= limit) {
392 while ((x2 = NextChange(x1)) <= limit && x2 <= (x1 + 2)) {
393 x1 = x2;
394 }
395 n = x1 - x0 + 1;
396 memcpy(&CurScreen(sp)->_line[y].text[x0],
397 &NewScreen(sp)->_line[y].text[x0],
398 n * sizeof(CurScreen(sp)->_line[y].text[x0]));
399 con_write(TCB,
400 y,
401 x0,
402 &CurScreen(sp)->_line[y].text[x0], n);
403 x0 = NextChange(x1);
404 }
405
406 /* mark line changed successfully */
407 if (y <= NewScreen(sp)->_maxy) {
408 MARK_NOCHANGE(NewScreen(sp), y);
409 }
410 if (y <= CurScreen(sp)->_maxy) {
411 MARK_NOCHANGE(CurScreen(sp), y);
412 }
413 #else
414 x1 = NewScreen(sp)->_line[y].lastchar;
415 n = x1 - x0 + 1;
416 if (n > 0) {
417 memcpy(&CurScreen(sp)->_line[y].text[x0],
418 &NewScreen(sp)->_line[y].text[x0],
419 (size_t) n * sizeof(CurScreen(sp)->_line[y].text[x0]));
420 con_write(TCB,
421 y,
422 x0,
423 &CurScreen(sp)->_line[y].text[x0], n);
424
425 /* mark line changed successfully */
426 if (y <= NewScreen(sp)->_maxy) {
427 MARK_NOCHANGE(NewScreen(sp), y);
428 }
429 if (y <= CurScreen(sp)->_maxy) {
430 MARK_NOCHANGE(CurScreen(sp), y);
431 }
432 }
433 #endif
434 }
435 }
436
437 /* put everything back in sync */
438 for (y = nonempty; y <= NewScreen(sp)->_maxy; y++) {
439 MARK_NOCHANGE(NewScreen(sp), y);
440 }
441 for (y = nonempty; y <= CurScreen(sp)->_maxy; y++) {
442 MARK_NOCHANGE(CurScreen(sp), y);
443 }
444
445 if (!NewScreen(sp)->_leaveok) {
446 CurScreen(sp)->_curx = NewScreen(sp)->_curx;
447 CurScreen(sp)->_cury = NewScreen(sp)->_cury;
448
449 TCB->drv->hwcur(TCB,
450 0, 0,
451 CurScreen(sp)->_cury, CurScreen(sp)->_curx);
452 }
453 selectActiveHandle(TCB);
454 result = OK;
455 }
456 returnCode(result);
457 }
458
459 static bool
drv_CanHandle(TERMINAL_CONTROL_BLOCK * TCB,const char * tname,int * errret GCC_UNUSED)460 drv_CanHandle(TERMINAL_CONTROL_BLOCK * TCB,
461 const char *tname,
462 int *errret GCC_UNUSED)
463 {
464 bool code = FALSE;
465
466 T((T_CALLED("win32con::drv_CanHandle(%p)"), TCB));
467
468 assert(TCB != 0);
469 assert(tname != 0);
470
471 TCB->magic = WINMAGIC;
472 if (*tname == 0 || *tname == 0 || *tname == '#') {
473 code = TRUE;
474 } else {
475 TERMINAL my_term;
476 int status;
477
478 code = FALSE;
479 #if (NCURSES_USE_DATABASE || NCURSES_USE_TERMCAP)
480 status = _nc_setup_tinfo(tname, &my_term.type);
481 #else
482 status = TGETENT_NO;
483 #endif
484 if (status != TGETENT_YES) {
485 const TERMTYPE *fallback = _nc_fallback(tname);
486
487 if (fallback) {
488 my_term.type = *fallback;
489 status = TGETENT_YES;
490 } else if (!strcmp(tname, "unknown")) {
491 code = TRUE;
492 }
493 }
494 if (status == TGETENT_YES) {
495 if (generic_type || hard_copy)
496 code = TRUE;
497 }
498 }
499
500 if (code) {
501 if ((TCB->term.type.Booleans) == 0) {
502 _nc_init_termtype(&(TCB->term.type));
503 }
504 }
505
506 returnBool(code);
507 }
508
509 static int
drv_dobeepflash(TERMINAL_CONTROL_BLOCK * TCB,int beepFlag GCC_UNUSED)510 drv_dobeepflash(TERMINAL_CONTROL_BLOCK * TCB,
511 int beepFlag GCC_UNUSED)
512 {
513 SCREEN *sp;
514 int res = ERR;
515
516 AssertTCB();
517 SetSP();
518
519 return res;
520 }
521
522 static int
drv_print(TERMINAL_CONTROL_BLOCK * TCB,char * data GCC_UNUSED,int len GCC_UNUSED)523 drv_print(TERMINAL_CONTROL_BLOCK * TCB,
524 char *data GCC_UNUSED,
525 int len GCC_UNUSED)
526 {
527 SCREEN *sp;
528
529 AssertTCB();
530 SetSP();
531
532 return ERR;
533 }
534
535 static int
drv_defaultcolors(TERMINAL_CONTROL_BLOCK * TCB,int fg GCC_UNUSED,int bg GCC_UNUSED)536 drv_defaultcolors(TERMINAL_CONTROL_BLOCK * TCB,
537 int fg GCC_UNUSED,
538 int bg GCC_UNUSED)
539 {
540 SCREEN *sp;
541 int code = ERR;
542
543 AssertTCB();
544 SetSP();
545
546 return (code);
547 }
548
549 static bool
get_SBI(TERMINAL_CONTROL_BLOCK * TCB)550 get_SBI(TERMINAL_CONTROL_BLOCK * TCB)
551 {
552 bool rc = FALSE;
553 Properties *p = PropOf(TCB);
554 if (GetConsoleScreenBufferInfo(TCB->hdl, &(p->SBI))) {
555 T(("GetConsoleScreenBufferInfo"));
556 T(("... buffer(X:%d Y:%d)",
557 p->SBI.dwSize.X,
558 p->SBI.dwSize.Y));
559 T(("... window(X:%d Y:%d)",
560 p->SBI.dwMaximumWindowSize.X,
561 p->SBI.dwMaximumWindowSize.Y));
562 T(("... cursor(X:%d Y:%d)",
563 p->SBI.dwCursorPosition.X,
564 p->SBI.dwCursorPosition.Y));
565 T(("... display(Top:%d Bottom:%d Left:%d Right:%d)",
566 p->SBI.srWindow.Top,
567 p->SBI.srWindow.Bottom,
568 p->SBI.srWindow.Left,
569 p->SBI.srWindow.Right));
570 if (p->buffered) {
571 p->origin.X = 0;
572 p->origin.Y = 0;
573 } else {
574 p->origin.X = p->SBI.srWindow.Left;
575 p->origin.Y = p->SBI.srWindow.Top;
576 }
577 rc = TRUE;
578 } else {
579 T(("GetConsoleScreenBufferInfo ERR"));
580 }
581 return rc;
582 }
583
584 static void
drv_setcolor(TERMINAL_CONTROL_BLOCK * TCB,int fore,int color,int (* outc)(SCREEN *,int)GCC_UNUSED)585 drv_setcolor(TERMINAL_CONTROL_BLOCK * TCB,
586 int fore,
587 int color,
588 int (*outc) (SCREEN *, int) GCC_UNUSED)
589 {
590 AssertTCB();
591
592 if (okConsoleHandle(TCB) &&
593 PropOf(TCB) != 0) {
594 WORD a = MapColor(fore, color);
595 a |= (WORD) ((PropOf(TCB)->SBI.wAttributes) & (fore ? 0xfff8 : 0xff8f));
596 SetConsoleTextAttribute(TCB->hdl, a);
597 get_SBI(TCB);
598 }
599 }
600
601 static bool
drv_rescol(TERMINAL_CONTROL_BLOCK * TCB)602 drv_rescol(TERMINAL_CONTROL_BLOCK * TCB)
603 {
604 bool res = FALSE;
605
606 AssertTCB();
607 if (okConsoleHandle(TCB)) {
608 WORD a = FOREGROUND_BLUE | FOREGROUND_RED | FOREGROUND_GREEN;
609 SetConsoleTextAttribute(TCB->hdl, a);
610 get_SBI(TCB);
611 res = TRUE;
612 }
613 return res;
614 }
615
616 static bool
drv_rescolors(TERMINAL_CONTROL_BLOCK * TCB)617 drv_rescolors(TERMINAL_CONTROL_BLOCK * TCB)
618 {
619 int result = FALSE;
620 SCREEN *sp;
621
622 AssertTCB();
623 SetSP();
624
625 return result;
626 }
627
628 static int
drv_size(TERMINAL_CONTROL_BLOCK * TCB,int * Lines,int * Cols)629 drv_size(TERMINAL_CONTROL_BLOCK * TCB, int *Lines, int *Cols)
630 {
631 int result = ERR;
632
633 AssertTCB();
634
635 T((T_CALLED("win32con::drv_size(%p)"), TCB));
636
637 if (okConsoleHandle(TCB) &&
638 PropOf(TCB) != 0 &&
639 Lines != NULL &&
640 Cols != NULL) {
641 if (PropOf(TCB)->buffered) {
642 *Lines = (int) (PropOf(TCB)->SBI.dwSize.Y);
643 *Cols = (int) (PropOf(TCB)->SBI.dwSize.X);
644 } else {
645 *Lines = (int) (PropOf(TCB)->SBI.srWindow.Bottom + 1 -
646 PropOf(TCB)->SBI.srWindow.Top);
647 *Cols = (int) (PropOf(TCB)->SBI.srWindow.Right + 1 -
648 PropOf(TCB)->SBI.srWindow.Left);
649 }
650 result = OK;
651 }
652 returnCode(result);
653 }
654
655 static int
drv_setsize(TERMINAL_CONTROL_BLOCK * TCB GCC_UNUSED,int l GCC_UNUSED,int c GCC_UNUSED)656 drv_setsize(TERMINAL_CONTROL_BLOCK * TCB GCC_UNUSED,
657 int l GCC_UNUSED,
658 int c GCC_UNUSED)
659 {
660 AssertTCB();
661 return ERR;
662 }
663
664 static int
drv_sgmode(TERMINAL_CONTROL_BLOCK * TCB,int setFlag,TTY * buf)665 drv_sgmode(TERMINAL_CONTROL_BLOCK * TCB, int setFlag, TTY * buf)
666 {
667 DWORD dwFlag = 0;
668 tcflag_t iflag;
669 tcflag_t lflag;
670
671 AssertTCB();
672
673 if (TCB == 0 || buf == NULL)
674 return ERR;
675
676 if (setFlag) {
677 iflag = buf->c_iflag;
678 lflag = buf->c_lflag;
679
680 GetConsoleMode(TCB->inp, &dwFlag);
681
682 if (lflag & ICANON)
683 dwFlag |= ENABLE_LINE_INPUT;
684 else
685 dwFlag &= (DWORD) (~ENABLE_LINE_INPUT);
686
687 if (lflag & ECHO)
688 dwFlag |= ENABLE_ECHO_INPUT;
689 else
690 dwFlag &= (DWORD) (~ENABLE_ECHO_INPUT);
691
692 if (iflag & BRKINT)
693 dwFlag |= ENABLE_PROCESSED_INPUT;
694 else
695 dwFlag &= (DWORD) (~ENABLE_PROCESSED_INPUT);
696
697 dwFlag |= ENABLE_MOUSE_INPUT;
698
699 buf->c_iflag = iflag;
700 buf->c_lflag = lflag;
701 SetConsoleMode(TCB->inp, dwFlag);
702 TCB->term.Nttyb = *buf;
703 } else {
704 iflag = TCB->term.Nttyb.c_iflag;
705 lflag = TCB->term.Nttyb.c_lflag;
706 GetConsoleMode(TCB->inp, &dwFlag);
707
708 if (dwFlag & ENABLE_LINE_INPUT)
709 lflag |= ICANON;
710 else
711 lflag &= (tcflag_t) (~ICANON);
712
713 if (dwFlag & ENABLE_ECHO_INPUT)
714 lflag |= ECHO;
715 else
716 lflag &= (tcflag_t) (~ECHO);
717
718 if (dwFlag & ENABLE_PROCESSED_INPUT)
719 iflag |= BRKINT;
720 else
721 iflag &= (tcflag_t) (~BRKINT);
722
723 TCB->term.Nttyb.c_iflag = iflag;
724 TCB->term.Nttyb.c_lflag = lflag;
725
726 *buf = TCB->term.Nttyb;
727 }
728 return OK;
729 }
730
731 static int
drv_mode(TERMINAL_CONTROL_BLOCK * TCB,int progFlag,int defFlag)732 drv_mode(TERMINAL_CONTROL_BLOCK * TCB, int progFlag, int defFlag)
733 {
734 SCREEN *sp;
735 TERMINAL *_term = (TERMINAL *) TCB;
736 int code = ERR;
737
738 AssertTCB();
739 sp = TCB->csp;
740
741 PropOf(TCB)->progMode = progFlag;
742 PropOf(TCB)->lastOut = progFlag ? TCB->hdl : TCB->out;
743 SetConsoleActiveScreenBuffer(PropOf(TCB)->lastOut);
744
745 if (progFlag) /* prog mode */ {
746 if (defFlag) {
747 if ((drv_sgmode(TCB, FALSE, &(_term->Nttyb)) == OK)) {
748 _term->Nttyb.c_oflag &= (tcflag_t) (~OFLAGS_TABS);
749 code = OK;
750 }
751 } else {
752 /* reset_prog_mode */
753 if (drv_sgmode(TCB, TRUE, &(_term->Nttyb)) == OK) {
754 if (sp) {
755 if (sp->_keypad_on)
756 _nc_keypad(sp, TRUE);
757 NC_BUFFERED(sp, TRUE);
758 }
759 code = OK;
760 }
761 }
762 } else { /* shell mode */
763 if (defFlag) {
764 /* def_shell_mode */
765 if (drv_sgmode(TCB, FALSE, &(_term->Ottyb)) == OK) {
766 code = OK;
767 }
768 } else {
769 /* reset_shell_mode */
770 if (sp) {
771 _nc_keypad(sp, FALSE);
772 NCURSES_SP_NAME(_nc_flush) (sp);
773 NC_BUFFERED(sp, FALSE);
774 }
775 code = drv_sgmode(TCB, TRUE, &(_term->Ottyb));
776 }
777 }
778
779 return (code);
780 }
781
782 static void
drv_screen_init(SCREEN * sp GCC_UNUSED)783 drv_screen_init(SCREEN *sp GCC_UNUSED)
784 {
785 }
786
787 static void
drv_wrap(SCREEN * sp GCC_UNUSED)788 drv_wrap(SCREEN *sp GCC_UNUSED)
789 {
790 }
791
792 static int
rkeycompare(const void * el1,const void * el2)793 rkeycompare(const void *el1, const void *el2)
794 {
795 WORD key1 = (LOWORD((*((const LONG *) el1)))) & 0x7fff;
796 WORD key2 = (LOWORD((*((const LONG *) el2)))) & 0x7fff;
797
798 return ((key1 < key2) ? -1 : ((key1 == key2) ? 0 : 1));
799 }
800
801 static int
keycompare(const void * el1,const void * el2)802 keycompare(const void *el1, const void *el2)
803 {
804 WORD key1 = HIWORD((*((const LONG *) el1)));
805 WORD key2 = HIWORD((*((const LONG *) el2)));
806
807 return ((key1 < key2) ? -1 : ((key1 == key2) ? 0 : 1));
808 }
809
810 static int
MapKey(TERMINAL_CONTROL_BLOCK * TCB,WORD vKey)811 MapKey(TERMINAL_CONTROL_BLOCK * TCB, WORD vKey)
812 {
813 WORD nKey = 0;
814 void *res;
815 LONG key = GenMap(vKey, 0);
816 int code = -1;
817
818 AssertTCB();
819
820 res = bsearch(&key,
821 PropOf(TCB)->map,
822 (size_t) (N_INI + FKEYS),
823 sizeof(keylist[0]),
824 keycompare);
825 if (res) {
826 key = *((LONG *) res);
827 nKey = LOWORD(key);
828 code = (int) (nKey & 0x7fff);
829 if (nKey & 0x8000)
830 code = -code;
831 }
832 return code;
833 }
834
835 static void
drv_release(TERMINAL_CONTROL_BLOCK * TCB)836 drv_release(TERMINAL_CONTROL_BLOCK * TCB)
837 {
838 T((T_CALLED("win32con::drv_release(%p)"), TCB));
839
840 AssertTCB();
841 if (TCB->prop)
842 free(TCB->prop);
843
844 returnVoid;
845 }
846
847 /*
848 * Attempt to save the screen contents. PDCurses does this if
849 * PDC_RESTORE_SCREEN is set, giving the same visual appearance on restoration
850 * as if the library had allocated a console buffer.
851 */
852 static bool
save_original_screen(TERMINAL_CONTROL_BLOCK * TCB)853 save_original_screen(TERMINAL_CONTROL_BLOCK * TCB)
854 {
855 bool result = FALSE;
856 Properties *p = PropOf(TCB);
857 COORD bufferSize;
858 COORD bufferCoord;
859 SMALL_RECT readRegion;
860 size_t want;
861
862 bufferSize.X = p->SBI.dwSize.X;
863 bufferSize.Y = p->SBI.dwSize.Y;
864 want = (size_t) (bufferSize.X * bufferSize.Y);
865
866 if ((p->save_screen = malloc(want * sizeof(CHAR_INFO))) != 0) {
867 bufferCoord.X = bufferCoord.Y = 0;
868
869 readRegion.Top = 0;
870 readRegion.Left = 0;
871 readRegion.Bottom = (SHORT) (bufferSize.Y - 1);
872 readRegion.Right = (SHORT) (bufferSize.X - 1);
873
874 T(("... reading console buffer %dx%d into %d,%d - %d,%d at %d,%d",
875 bufferSize.Y, bufferSize.X,
876 readRegion.Top,
877 readRegion.Left,
878 readRegion.Bottom,
879 readRegion.Right,
880 bufferCoord.Y,
881 bufferCoord.X));
882
883 if (ReadConsoleOutput(TCB->hdl,
884 p->save_screen,
885 bufferSize,
886 bufferCoord,
887 &readRegion)) {
888 result = TRUE;
889 } else {
890 T((" error %#lx", (unsigned long) GetLastError()));
891 FreeAndNull(p->save_screen);
892
893 bufferSize.X = (SHORT) (p->SBI.srWindow.Right
894 - p->SBI.srWindow.Left + 1);
895 bufferSize.Y = (SHORT) (p->SBI.srWindow.Bottom
896 - p->SBI.srWindow.Top + 1);
897 want = (size_t) (bufferSize.X * bufferSize.Y);
898
899 if ((p->save_screen = malloc(want * sizeof(CHAR_INFO))) != 0) {
900 bufferCoord.X = bufferCoord.Y = 0;
901
902 readRegion.Top = p->SBI.srWindow.Top;
903 readRegion.Left = p->SBI.srWindow.Left;
904 readRegion.Bottom = p->SBI.srWindow.Bottom;
905 readRegion.Right = p->SBI.srWindow.Right;
906
907 T(("... reading console window %dx%d into %d,%d - %d,%d at %d,%d",
908 bufferSize.Y, bufferSize.X,
909 readRegion.Top,
910 readRegion.Left,
911 readRegion.Bottom,
912 readRegion.Right,
913 bufferCoord.Y,
914 bufferCoord.X));
915
916 if (ReadConsoleOutput(TCB->hdl,
917 p->save_screen,
918 bufferSize,
919 bufferCoord,
920 &readRegion)) {
921 result = TRUE;
922 } else {
923 T((" error %#lx", (unsigned long) GetLastError()));
924 }
925 }
926 }
927 }
928
929 T(("... save original screen contents %s", result ? "ok" : "err"));
930 return result;
931 }
932
933 static void
drv_init(TERMINAL_CONTROL_BLOCK * TCB)934 drv_init(TERMINAL_CONTROL_BLOCK * TCB)
935 {
936 DWORD num_buttons;
937
938 T((T_CALLED("win32con::drv_init(%p)"), TCB));
939
940 AssertTCB();
941
942 if (TCB) {
943 BOOL b = AllocConsole();
944 WORD a;
945 int i;
946 bool buffered = TRUE;
947
948 if (!b)
949 b = AttachConsole(ATTACH_PARENT_PROCESS);
950
951 TCB->inp = GetStdHandle(STD_INPUT_HANDLE);
952 TCB->out = GetStdHandle(STD_OUTPUT_HANDLE);
953
954 if (getenv("NCGDB")) {
955 TCB->hdl = TCB->out;
956 buffered = FALSE;
957 } else {
958 TCB->hdl = CreateConsoleScreenBuffer(GENERIC_READ | GENERIC_WRITE,
959 0,
960 NULL,
961 CONSOLE_TEXTMODE_BUFFER,
962 NULL);
963 }
964
965 if (InvalidConsoleHandle(TCB->hdl)) {
966 returnVoid;
967 } else if ((TCB->prop = typeCalloc(Properties, 1)) != 0) {
968 PropOf(TCB)->buffered = buffered;
969 if (!get_SBI(TCB)) {
970 FreeAndNull(TCB->prop); /* force error in drv_size */
971 returnVoid;
972 }
973 if (!buffered) {
974 if (!save_original_screen(TCB)) {
975 FreeAndNull(TCB->prop); /* force error in drv_size */
976 returnVoid;
977 }
978 }
979 }
980
981 TCB->info.initcolor = TRUE;
982 TCB->info.canchange = FALSE;
983 TCB->info.hascolor = TRUE;
984 TCB->info.caninit = TRUE;
985
986 TCB->info.maxpairs = NUMPAIRS;
987 TCB->info.maxcolors = 8;
988 TCB->info.numlabels = 0;
989 TCB->info.labelwidth = 0;
990 TCB->info.labelheight = 0;
991 TCB->info.nocolorvideo = 1;
992 TCB->info.tabsize = 8;
993
994 if (GetNumberOfConsoleMouseButtons(&num_buttons)) {
995 T(("mouse has %ld buttons", num_buttons));
996 TCB->info.numbuttons = (int) num_buttons;
997 } else {
998 TCB->info.numbuttons = 1;
999 }
1000
1001 TCB->info.defaultPalette = _nc_cga_palette;
1002
1003 for (i = 0; i < (N_INI + FKEYS); i++) {
1004 if (i < N_INI)
1005 PropOf(TCB)->rmap[i] = PropOf(TCB)->map[i] = (DWORD) keylist[i];
1006 else
1007 PropOf(TCB)->rmap[i] = PropOf(TCB)->map[i] =
1008 GenMap((VK_F1 + (i - N_INI)), (KEY_F(1) + (i - N_INI)));
1009 }
1010 qsort(PropOf(TCB)->map,
1011 (size_t) (MAPSIZE),
1012 sizeof(keylist[0]),
1013 keycompare);
1014 qsort(PropOf(TCB)->rmap,
1015 (size_t) (MAPSIZE),
1016 sizeof(keylist[0]),
1017 rkeycompare);
1018
1019 a = MapColor(true, COLOR_WHITE) | MapColor(false, COLOR_BLACK);
1020 for (i = 0; i < NUMPAIRS; i++)
1021 PropOf(TCB)->pairs[i] = a;
1022 }
1023 returnVoid;
1024 }
1025
1026 static void
drv_initpair(TERMINAL_CONTROL_BLOCK * TCB,int pair,int f,int b)1027 drv_initpair(TERMINAL_CONTROL_BLOCK * TCB,
1028 int pair,
1029 int f,
1030 int b)
1031 {
1032 SCREEN *sp;
1033
1034 AssertTCB();
1035 SetSP();
1036
1037 if ((pair > 0) && (pair < NUMPAIRS) && (f >= 0) && (f < 8)
1038 && (b >= 0) && (b < 8)) {
1039 PropOf(TCB)->pairs[pair] = MapColor(true, f) | MapColor(false, b);
1040 }
1041 }
1042
1043 static void
drv_initcolor(TERMINAL_CONTROL_BLOCK * TCB,int color GCC_UNUSED,int r GCC_UNUSED,int g GCC_UNUSED,int b GCC_UNUSED)1044 drv_initcolor(TERMINAL_CONTROL_BLOCK * TCB,
1045 int color GCC_UNUSED,
1046 int r GCC_UNUSED,
1047 int g GCC_UNUSED,
1048 int b GCC_UNUSED)
1049 {
1050 SCREEN *sp;
1051
1052 AssertTCB();
1053 SetSP();
1054 }
1055
1056 static void
drv_do_color(TERMINAL_CONTROL_BLOCK * TCB,int old_pair GCC_UNUSED,int pair GCC_UNUSED,int reverse GCC_UNUSED,int (* outc)(SCREEN *,int)GCC_UNUSED)1057 drv_do_color(TERMINAL_CONTROL_BLOCK * TCB,
1058 int old_pair GCC_UNUSED,
1059 int pair GCC_UNUSED,
1060 int reverse GCC_UNUSED,
1061 int (*outc) (SCREEN *, int) GCC_UNUSED
1062 )
1063 {
1064 SCREEN *sp;
1065
1066 AssertTCB();
1067 SetSP();
1068 }
1069
1070 static void
drv_initmouse(TERMINAL_CONTROL_BLOCK * TCB)1071 drv_initmouse(TERMINAL_CONTROL_BLOCK * TCB)
1072 {
1073 SCREEN *sp;
1074
1075 AssertTCB();
1076 SetSP();
1077
1078 sp->_mouse_type = M_TERM_DRIVER;
1079 }
1080
1081 static int
drv_testmouse(TERMINAL_CONTROL_BLOCK * TCB,int delay)1082 drv_testmouse(TERMINAL_CONTROL_BLOCK * TCB, int delay)
1083 {
1084 int rc = 0;
1085 SCREEN *sp;
1086
1087 AssertTCB();
1088 SetSP();
1089
1090 if (sp->_drv_mouse_head < sp->_drv_mouse_tail) {
1091 rc = TW_MOUSE;
1092 } else {
1093 rc = TCBOf(sp)->drv->twait(TCBOf(sp),
1094 TWAIT_MASK,
1095 delay,
1096 (int *) 0
1097 EVENTLIST_2nd(evl));
1098 }
1099
1100 return rc;
1101 }
1102
1103 static int
drv_mvcur(TERMINAL_CONTROL_BLOCK * TCB,int yold GCC_UNUSED,int xold GCC_UNUSED,int y,int x)1104 drv_mvcur(TERMINAL_CONTROL_BLOCK * TCB,
1105 int yold GCC_UNUSED, int xold GCC_UNUSED,
1106 int y, int x)
1107 {
1108 int ret = ERR;
1109 if (okConsoleHandle(TCB)) {
1110 Properties *p = PropOf(TCB);
1111 COORD loc;
1112 loc.X = (short) x;
1113 loc.Y = (short) (y + AdjustY(p));
1114 SetConsoleCursorPosition(TCB->hdl, loc);
1115 ret = OK;
1116 }
1117 return ret;
1118 }
1119
1120 static void
drv_hwlabel(TERMINAL_CONTROL_BLOCK * TCB,int labnum GCC_UNUSED,char * text GCC_UNUSED)1121 drv_hwlabel(TERMINAL_CONTROL_BLOCK * TCB,
1122 int labnum GCC_UNUSED,
1123 char *text GCC_UNUSED)
1124 {
1125 SCREEN *sp;
1126
1127 AssertTCB();
1128 SetSP();
1129 }
1130
1131 static void
drv_hwlabelOnOff(TERMINAL_CONTROL_BLOCK * TCB,int OnFlag GCC_UNUSED)1132 drv_hwlabelOnOff(TERMINAL_CONTROL_BLOCK * TCB,
1133 int OnFlag GCC_UNUSED)
1134 {
1135 SCREEN *sp;
1136
1137 AssertTCB();
1138 SetSP();
1139 }
1140
1141 static chtype
drv_conattr(TERMINAL_CONTROL_BLOCK * TCB GCC_UNUSED)1142 drv_conattr(TERMINAL_CONTROL_BLOCK * TCB GCC_UNUSED)
1143 {
1144 chtype res = A_NORMAL;
1145 res |= (A_BOLD | A_DIM | A_REVERSE | A_STANDOUT | A_COLOR);
1146 return res;
1147 }
1148
1149 static void
drv_setfilter(TERMINAL_CONTROL_BLOCK * TCB)1150 drv_setfilter(TERMINAL_CONTROL_BLOCK * TCB)
1151 {
1152 SCREEN *sp;
1153
1154 AssertTCB();
1155 SetSP();
1156 }
1157
1158 static void
drv_initacs(TERMINAL_CONTROL_BLOCK * TCB,chtype * real_map GCC_UNUSED,chtype * fake_map GCC_UNUSED)1159 drv_initacs(TERMINAL_CONTROL_BLOCK * TCB,
1160 chtype *real_map GCC_UNUSED,
1161 chtype *fake_map GCC_UNUSED)
1162 {
1163 #define DATA(a,b) { a, b }
1164 static struct {
1165 int acs_code;
1166 int use_code;
1167 } table[] = {
1168 DATA('a', 0xb1), /* ACS_CKBOARD */
1169 DATA('f', 0xf8), /* ACS_DEGREE */
1170 DATA('g', 0xf1), /* ACS_PLMINUS */
1171 DATA('j', 0xd9), /* ACS_LRCORNER */
1172 DATA('l', 0xda), /* ACS_ULCORNER */
1173 DATA('k', 0xbf), /* ACS_URCORNER */
1174 DATA('m', 0xc0), /* ACS_LLCORNER */
1175 DATA('n', 0xc5), /* ACS_PLUS */
1176 DATA('q', 0xc4), /* ACS_HLINE */
1177 DATA('t', 0xc3), /* ACS_LTEE */
1178 DATA('u', 0xb4), /* ACS_RTEE */
1179 DATA('v', 0xc1), /* ACS_BTEE */
1180 DATA('w', 0xc2), /* ACS_TTEE */
1181 DATA('x', 0xb3), /* ACS_VLINE */
1182 DATA('y', 0xf3), /* ACS_LEQUAL */
1183 DATA('z', 0xf2), /* ACS_GEQUAL */
1184 DATA('0', 0xdb), /* ACS_BLOCK */
1185 DATA('{', 0xe3), /* ACS_PI */
1186 DATA('}', 0x9c), /* ACS_STERLING */
1187 DATA(',', 0xae), /* ACS_LARROW */
1188 DATA('+', 0xaf), /* ACS_RARROW */
1189 DATA('~', 0xf9), /* ACS_BULLET */
1190 };
1191 #undef DATA
1192 unsigned n;
1193
1194 SCREEN *sp;
1195 AssertTCB();
1196 SetSP();
1197
1198 for (n = 0; n < SIZEOF(table); ++n) {
1199 real_map[table[n].acs_code] = (chtype) table[n].use_code | A_ALTCHARSET;
1200 if (sp != 0)
1201 sp->_screen_acs_map[table[n].acs_code] = TRUE;
1202 }
1203 }
1204
1205 static ULONGLONG
tdiff(FILETIME fstart,FILETIME fend)1206 tdiff(FILETIME fstart, FILETIME fend)
1207 {
1208 ULARGE_INTEGER ustart;
1209 ULARGE_INTEGER uend;
1210 ULONGLONG diff;
1211
1212 ustart.LowPart = fstart.dwLowDateTime;
1213 ustart.HighPart = fstart.dwHighDateTime;
1214 uend.LowPart = fend.dwLowDateTime;
1215 uend.HighPart = fend.dwHighDateTime;
1216
1217 diff = (uend.QuadPart - ustart.QuadPart) / 10000;
1218 return diff;
1219 }
1220
1221 static int
Adjust(int milliseconds,int diff)1222 Adjust(int milliseconds, int diff)
1223 {
1224 if (milliseconds == INFINITY)
1225 return milliseconds;
1226 milliseconds -= diff;
1227 if (milliseconds < 0)
1228 milliseconds = 0;
1229 return milliseconds;
1230 }
1231
1232 #define BUTTON_MASK (FROM_LEFT_1ST_BUTTON_PRESSED | \
1233 FROM_LEFT_2ND_BUTTON_PRESSED | \
1234 FROM_LEFT_3RD_BUTTON_PRESSED | \
1235 FROM_LEFT_4TH_BUTTON_PRESSED | \
1236 RIGHTMOST_BUTTON_PRESSED)
1237
1238 static int
decode_mouse(TERMINAL_CONTROL_BLOCK * TCB,int mask)1239 decode_mouse(TERMINAL_CONTROL_BLOCK * TCB, int mask)
1240 {
1241 SCREEN *sp;
1242 int result = 0;
1243
1244 AssertTCB();
1245 SetSP();
1246
1247 if (mask & FROM_LEFT_1ST_BUTTON_PRESSED)
1248 result |= BUTTON1_PRESSED;
1249 if (mask & FROM_LEFT_2ND_BUTTON_PRESSED)
1250 result |= BUTTON2_PRESSED;
1251 if (mask & FROM_LEFT_3RD_BUTTON_PRESSED)
1252 result |= BUTTON3_PRESSED;
1253 if (mask & FROM_LEFT_4TH_BUTTON_PRESSED)
1254 result |= BUTTON4_PRESSED;
1255
1256 if (mask & RIGHTMOST_BUTTON_PRESSED) {
1257 switch (TCB->info.numbuttons) {
1258 case 1:
1259 result |= BUTTON1_PRESSED;
1260 break;
1261 case 2:
1262 result |= BUTTON2_PRESSED;
1263 break;
1264 case 3:
1265 result |= BUTTON3_PRESSED;
1266 break;
1267 case 4:
1268 result |= BUTTON4_PRESSED;
1269 break;
1270 }
1271 }
1272
1273 return result;
1274 }
1275
1276 static int
drv_twait(TERMINAL_CONTROL_BLOCK * TCB,int mode,int milliseconds,int * timeleft EVENTLIST_2nd (_nc_eventlist * evl))1277 drv_twait(TERMINAL_CONTROL_BLOCK * TCB,
1278 int mode,
1279 int milliseconds,
1280 int *timeleft
1281 EVENTLIST_2nd(_nc_eventlist * evl))
1282 {
1283 SCREEN *sp;
1284 INPUT_RECORD inp_rec;
1285 BOOL b;
1286 DWORD nRead = 0, rc = (DWORD) (-1);
1287 int code = 0;
1288 FILETIME fstart;
1289 FILETIME fend;
1290 int diff;
1291 bool isImmed = (milliseconds == 0);
1292
1293 #define CONSUME() ReadConsoleInput(TCB->inp,&inp_rec,1,&nRead)
1294
1295 AssertTCB();
1296 SetSP();
1297
1298 TR(TRACE_IEVENT, ("start twait: %d milliseconds, mode: %d",
1299 milliseconds, mode));
1300
1301 if (milliseconds < 0)
1302 milliseconds = INFINITY;
1303
1304 memset(&inp_rec, 0, sizeof(inp_rec));
1305
1306 while (true) {
1307 GetSystemTimeAsFileTime(&fstart);
1308 rc = WaitForSingleObject(TCB->inp, (DWORD) milliseconds);
1309 GetSystemTimeAsFileTime(&fend);
1310 diff = (int) tdiff(fstart, fend);
1311 milliseconds = Adjust(milliseconds, diff);
1312
1313 if (!isImmed && milliseconds == 0)
1314 break;
1315
1316 if (rc == WAIT_OBJECT_0) {
1317 if (mode) {
1318 b = GetNumberOfConsoleInputEvents(TCB->inp, &nRead);
1319 if (b && nRead > 0) {
1320 b = PeekConsoleInput(TCB->inp, &inp_rec, 1, &nRead);
1321 if (b && nRead > 0) {
1322 switch (inp_rec.EventType) {
1323 case KEY_EVENT:
1324 if (mode & TW_INPUT) {
1325 WORD vk = inp_rec.Event.KeyEvent.wVirtualKeyCode;
1326 char ch = inp_rec.Event.KeyEvent.uChar.AsciiChar;
1327
1328 if (inp_rec.Event.KeyEvent.bKeyDown) {
1329 if (0 == ch) {
1330 int nKey = MapKey(TCB, vk);
1331 if ((nKey < 0) || FALSE == sp->_keypad_on) {
1332 CONSUME();
1333 continue;
1334 }
1335 }
1336 code = TW_INPUT;
1337 goto end;
1338 } else {
1339 CONSUME();
1340 }
1341 }
1342 continue;
1343 case MOUSE_EVENT:
1344 if (decode_mouse(TCB,
1345 (inp_rec.Event.MouseEvent.dwButtonState
1346 & BUTTON_MASK)) == 0) {
1347 CONSUME();
1348 } else if (mode & TW_MOUSE) {
1349 code = TW_MOUSE;
1350 goto end;
1351 }
1352 continue;
1353 default:
1354 selectActiveHandle(TCB);
1355 continue;
1356 }
1357 }
1358 }
1359 }
1360 continue;
1361 } else {
1362 if (rc != WAIT_TIMEOUT) {
1363 code = -1;
1364 break;
1365 } else {
1366 code = 0;
1367 break;
1368 }
1369 }
1370 }
1371 end:
1372
1373 TR(TRACE_IEVENT, ("end twait: returned %d (%d), remaining time %d msec",
1374 code, errno, milliseconds));
1375
1376 if (timeleft)
1377 *timeleft = milliseconds;
1378
1379 return code;
1380 }
1381
1382 static bool
handle_mouse(TERMINAL_CONTROL_BLOCK * TCB,MOUSE_EVENT_RECORD mer)1383 handle_mouse(TERMINAL_CONTROL_BLOCK * TCB, MOUSE_EVENT_RECORD mer)
1384 {
1385 SCREEN *sp;
1386 MEVENT work;
1387 bool result = FALSE;
1388
1389 AssertTCB();
1390 SetSP();
1391
1392 sp->_drv_mouse_old_buttons = sp->_drv_mouse_new_buttons;
1393 sp->_drv_mouse_new_buttons = mer.dwButtonState & BUTTON_MASK;
1394
1395 /*
1396 * We're only interested if the button is pressed or released.
1397 * FIXME: implement continuous event-tracking.
1398 */
1399 if (sp->_drv_mouse_new_buttons != sp->_drv_mouse_old_buttons) {
1400 Properties *p = PropOf(TCB);
1401
1402 memset(&work, 0, sizeof(work));
1403
1404 if (sp->_drv_mouse_new_buttons) {
1405
1406 work.bstate |= (mmask_t) decode_mouse(TCB, sp->_drv_mouse_new_buttons);
1407
1408 } else {
1409
1410 /* cf: BUTTON_PRESSED, BUTTON_RELEASED */
1411 work.bstate |= (mmask_t) (decode_mouse(TCB,
1412 sp->_drv_mouse_old_buttons)
1413 >> 1);
1414
1415 result = TRUE;
1416 }
1417
1418 work.x = mer.dwMousePosition.X;
1419 work.y = mer.dwMousePosition.Y - AdjustY(p);
1420
1421 sp->_drv_mouse_fifo[sp->_drv_mouse_tail] = work;
1422 sp->_drv_mouse_tail += 1;
1423 }
1424
1425 return result;
1426 }
1427
1428 static int
drv_read(TERMINAL_CONTROL_BLOCK * TCB,int * buf)1429 drv_read(TERMINAL_CONTROL_BLOCK * TCB, int *buf)
1430 {
1431 SCREEN *sp;
1432 int n = 1;
1433 INPUT_RECORD inp_rec;
1434 BOOL b;
1435 DWORD nRead;
1436 WORD vk;
1437
1438 AssertTCB();
1439 assert(buf);
1440 SetSP();
1441
1442 memset(&inp_rec, 0, sizeof(inp_rec));
1443
1444 T((T_CALLED("win32con::drv_read(%p)"), TCB));
1445 while ((b = ReadConsoleInput(TCB->inp, &inp_rec, 1, &nRead))) {
1446 if (b && nRead > 0) {
1447 if (inp_rec.EventType == KEY_EVENT) {
1448 if (!inp_rec.Event.KeyEvent.bKeyDown)
1449 continue;
1450 *buf = (int) inp_rec.Event.KeyEvent.uChar.AsciiChar;
1451 vk = inp_rec.Event.KeyEvent.wVirtualKeyCode;
1452 if (*buf == 0) {
1453 if (sp->_keypad_on) {
1454 *buf = MapKey(TCB, vk);
1455 if (0 > (*buf))
1456 continue;
1457 else
1458 break;
1459 } else
1460 continue;
1461 } else { /* *buf != 0 */
1462 break;
1463 }
1464 } else if (inp_rec.EventType == MOUSE_EVENT) {
1465 if (handle_mouse(TCB, inp_rec.Event.MouseEvent)) {
1466 *buf = KEY_MOUSE;
1467 break;
1468 }
1469 }
1470 continue;
1471 }
1472 }
1473 returnCode(n);
1474 }
1475
1476 static int
drv_nap(TERMINAL_CONTROL_BLOCK * TCB GCC_UNUSED,int ms)1477 drv_nap(TERMINAL_CONTROL_BLOCK * TCB GCC_UNUSED, int ms)
1478 {
1479 T((T_CALLED("win32con::drv_nap(%p, %d)"), TCB, ms));
1480 Sleep((DWORD) ms);
1481 returnCode(OK);
1482 }
1483
1484 static bool
drv_kyExist(TERMINAL_CONTROL_BLOCK * TCB,int keycode)1485 drv_kyExist(TERMINAL_CONTROL_BLOCK * TCB, int keycode)
1486 {
1487 SCREEN *sp;
1488 WORD nKey;
1489 void *res;
1490 bool found = FALSE;
1491 LONG key = GenMap(0, (WORD) keycode);
1492
1493 AssertTCB();
1494 SetSP();
1495
1496 AssertTCB();
1497
1498 T((T_CALLED("win32con::drv_kyExist(%p, %d)"), TCB, keycode));
1499 res = bsearch(&key,
1500 PropOf(TCB)->rmap,
1501 (size_t) (N_INI + FKEYS),
1502 sizeof(keylist[0]),
1503 rkeycompare);
1504 if (res) {
1505 key = *((LONG *) res);
1506 nKey = LOWORD(key);
1507 if (!(nKey & 0x8000))
1508 found = TRUE;
1509 }
1510 returnCode(found);
1511 }
1512
1513 static int
drv_kpad(TERMINAL_CONTROL_BLOCK * TCB,int flag GCC_UNUSED)1514 drv_kpad(TERMINAL_CONTROL_BLOCK * TCB, int flag GCC_UNUSED)
1515 {
1516 SCREEN *sp;
1517 int code = ERR;
1518
1519 AssertTCB();
1520 sp = TCB->csp;
1521
1522 T((T_CALLED("win32con::drv_kpad(%p, %d)"), TCB, flag));
1523 if (sp) {
1524 code = OK;
1525 }
1526 returnCode(code);
1527 }
1528
1529 static int
drv_keyok(TERMINAL_CONTROL_BLOCK * TCB,int keycode,int flag)1530 drv_keyok(TERMINAL_CONTROL_BLOCK * TCB, int keycode, int flag)
1531 {
1532 int code = ERR;
1533 SCREEN *sp;
1534 WORD nKey;
1535 WORD vKey;
1536 void *res;
1537 LONG key = GenMap(0, (WORD) keycode);
1538
1539 AssertTCB();
1540 SetSP();
1541
1542 T((T_CALLED("win32con::drv_keyok(%p, %d, %d)"), TCB, keycode, flag));
1543 if (sp) {
1544 res = bsearch(&key,
1545 PropOf(TCB)->rmap,
1546 (size_t) (N_INI + FKEYS),
1547 sizeof(keylist[0]),
1548 rkeycompare);
1549 if (res) {
1550 key = *((LONG *) res);
1551 vKey = HIWORD(key);
1552 nKey = (LOWORD(key)) & 0x7fff;
1553 if (!flag)
1554 nKey |= 0x8000;
1555 *(LONG *) res = GenMap(vKey, nKey);
1556 }
1557 }
1558 returnCode(code);
1559 }
1560
1561 NCURSES_EXPORT_VAR (TERM_DRIVER) _nc_WIN_DRIVER = {
1562 FALSE,
1563 drv_CanHandle, /* CanHandle */
1564 drv_init, /* init */
1565 drv_release, /* release */
1566 drv_size, /* size */
1567 drv_sgmode, /* sgmode */
1568 drv_conattr, /* conattr */
1569 drv_mvcur, /* hwcur */
1570 drv_mode, /* mode */
1571 drv_rescol, /* rescol */
1572 drv_rescolors, /* rescolors */
1573 drv_setcolor, /* color */
1574 drv_dobeepflash, /* DoBeepFlash */
1575 drv_initpair, /* initpair */
1576 drv_initcolor, /* initcolor */
1577 drv_do_color, /* docolor */
1578 drv_initmouse, /* initmouse */
1579 drv_testmouse, /* testmouse */
1580 drv_setfilter, /* setfilter */
1581 drv_hwlabel, /* hwlabel */
1582 drv_hwlabelOnOff, /* hwlabelOnOff */
1583 drv_doupdate, /* update */
1584 drv_defaultcolors, /* defaultcolors */
1585 drv_print, /* print */
1586 drv_size, /* getsize */
1587 drv_setsize, /* setsize */
1588 drv_initacs, /* initacs */
1589 drv_screen_init, /* scinit */
1590 drv_wrap, /* scexit */
1591 drv_twait, /* twait */
1592 drv_read, /* read */
1593 drv_nap, /* nap */
1594 drv_kpad, /* kpad */
1595 drv_keyok, /* kyOk */
1596 drv_kyExist /* kyExist */
1597 };
1598