1 /****************************************************************************
2 * Copyright (c) 1998-2013,2014 Free Software Foundation, Inc. *
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: *
12 * The above copyright notice and this permission notice shall be included *
13 * in all copies or substantial portions of the Software. *
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. *
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 *
27 ****************************************************************************/
29 /****************************************************************************
30 * Author: Juergen Pfeifer *
31 * and: Thomas E. Dickey *
32 ****************************************************************************/
35 * TODO - GetMousePos(POINT * result) from ntconio.c
36 * TODO - implement nodelay
39 #include <curses.priv.h>
40 #define CUR my_term.type.
42 MODULE_ID("$Id: win_driver.c,v 1.31 2014/04/13 00:16:07 tom Exp $")
44 #define WINMAGIC NCDRV_MAGIC(NCDRV_WINCONSOLE)
46 #define EXP_OPTIMIZE 0
48 #define okConsoleHandle(TCB) (TCB != 0 && !InvalidConsoleHandle(TCB->hdl))
50 #define AssertTCB() assert(TCB != 0 && (TCB->magic == WINMAGIC))
51 #define SetSP() assert(TCB->csp != 0); sp = TCB->csp; (void) sp
53 #define GenMap(vKey,key) MAKELONG(key, vKey)
55 #define AdjustY(p) ((p)->buffered ? 0 : (int) (p)->SBI.srWindow.Top)
57 static const LONG keylist[] =
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)
70 #define N_INI ((int)(sizeof(keylist)/sizeof(keylist[0])))
72 #define MAPSIZE (FKEYS + N_INI)
75 typedef struct props {
76 CONSOLE_SCREEN_BUFFER_INFO SBI;
82 bool buffered; /* normally allocate console-buffer */
83 bool window_only; /* ..if not, we save buffer or window-only */
85 CHAR_INFO *save_screen;
88 #define PropOf(TCB) ((Properties*)TCB->prop)
91 _nc_mingw_ioctl(int fd GCC_UNUSED,
92 long int request GCC_UNUSED,
93 struct termios *arg GCC_UNUSED)
97 fprintf(stderr, "TERMINFO currently not supported on Windows.\n");
102 MapColor(bool fore, int color)
104 static const int _cmap[] =
105 {0, 4, 2, 6, 1, 5, 3, 7};
107 if (color < 0 || color > 7)
117 MapAttr(TERMINAL_CONTROL_BLOCK * TCB, WORD res, attr_t ch)
126 if (p > 0 && p < NUMPAIRS && TCB != 0 && sp != 0) {
128 a = PropOf(TCB)->pairs[p];
129 res = (WORD) ((res & 0xff00) | a);
133 if (ch & A_REVERSE) {
134 res = (WORD) ((res & 0xff00) |
135 (((res & 0x07) << 4) |
136 ((res & 0x70) >> 4)));
139 if (ch & A_STANDOUT) {
140 res = (WORD) ((res & 0xff00) |
141 (((res & 0x07) << 4) |
142 ((res & 0x70) >> 4)) |
143 BACKGROUND_INTENSITY);
147 res |= FOREGROUND_INTENSITY;
150 res |= BACKGROUND_INTENSITY;
155 #if USE_WIDEC_SUPPORT
157 * TODO: support surrogate pairs
158 * TODO: support combining characters
160 * TODO: check wcwidth of base character, fill if needed for double-width
161 * TODO: _nc_wacs should be part of sp.
164 con_write16(TERMINAL_CONTROL_BLOCK * TCB, int y, int x, cchar_t *str, int limit)
173 Properties *p = PropOf(TCB);
179 for (i = actual = 0; i < limit; i++) {
183 ci[actual].Char.UnicodeChar = CharOf(ch);
184 ci[actual].Attributes = MapAttr(TCB,
185 PropOf(TCB)->SBI.wAttributes,
187 if (AttrOf(ch) & A_ALTCHARSET) {
189 int which = CharOf(ch);
192 && CharOf(_nc_wacs[which]) != 0) {
193 ci[actual].Char.UnicodeChar = CharOf(_nc_wacs[which]);
195 ci[actual].Char.UnicodeChar = ' ';
204 siz.X = (short) actual;
207 rec.Left = (short) x;
208 rec.Top = (SHORT) (y + AdjustY(p));
209 rec.Right = (short) (x + limit - 1);
210 rec.Bottom = rec.Top;
212 return WriteConsoleOutputW(TCB->hdl, ci, siz, loc, &rec);
214 #define con_write(tcb, y, x, str, n) con_write16(tcb, y, x, str, n)
217 con_write8(TERMINAL_CONTROL_BLOCK * TCB, int y, int x, chtype *str, int n)
230 for (i = 0; i < n; i++) {
232 ci[i].Char.AsciiChar = ChCharOf(ch);
233 ci[i].Attributes = MapAttr(TCB,
234 PropOf(TCB)->SBI.wAttributes,
236 if (ChAttrOf(ch) & A_ALTCHARSET) {
238 ci[i].Char.AsciiChar =
239 ChCharOf(NCURSES_SP_NAME(_nc_acs_char) (sp, ChCharOf(ch)));
248 rec.Left = (short) x;
250 rec.Right = (short) (x + n - 1);
251 rec.Bottom = rec.Top;
253 return WriteConsoleOutput(TCB->hdl, ci, siz, loc, &rec);
255 #define con_write(tcb, y, x, str, n) con_write8(tcb, y, x, str, n)
260 * Comparing new/current screens, determine the last column-index for a change
261 * beginning on the given row,col position. Unlike a serial terminal, there is
262 * no cost for "moving" the "cursor" on the line as we update it.
265 find_end_of_change(SCREEN *sp, int row, int col)
268 struct ldat *curdat = CurScreen(sp)->_line + row;
269 struct ldat *newdat = NewScreen(sp)->_line + row;
271 while (col <= newdat->lastchar) {
272 #if USE_WIDEC_SUPPORT
273 if (isWidecExt(curdat->text[col]) || isWidecExt(newdat->text[col])) {
275 } else if (memcmp(&curdat->text[col],
277 sizeof(curdat->text[0]))) {
283 if (curdat->text[col] != newdat->text[col]) {
295 * Given a row,col position at the end of a change-chunk, look for the
296 * beginning of the next change-chunk.
299 find_next_change(SCREEN *sp, int row, int col)
301 struct ldat *curdat = CurScreen(sp)->_line + row;
302 struct ldat *newdat = NewScreen(sp)->_line + row;
303 int result = newdat->lastchar + 1;
305 while (++col <= newdat->lastchar) {
306 #if USE_WIDEC_SUPPORT
307 if (isWidecExt(curdat->text[col]) != isWidecExt(newdat->text[col])) {
310 } else if (memcmp(&curdat->text[col],
312 sizeof(curdat->text[0]))) {
317 if (curdat->text[col] != newdat->text[col]) {
326 #define EndChange(first) \
327 find_end_of_change(sp, y, first)
328 #define NextChange(last) \
329 find_next_change(sp, y, last)
331 #endif /* EXP_OPTIMIZE */
333 #define MARK_NOCHANGE(win,row) \
334 win->_line[row].firstchar = _NOCHANGE; \
335 win->_line[row].lastchar = _NOCHANGE
338 selectActiveHandle(TERMINAL_CONTROL_BLOCK * TCB)
340 if (PropOf(TCB)->lastOut != TCB->hdl) {
341 PropOf(TCB)->lastOut = TCB->hdl;
342 SetConsoleActiveScreenBuffer(PropOf(TCB)->lastOut);
347 restore_original_screen(TERMINAL_CONTROL_BLOCK * TCB)
350 SMALL_RECT writeRegion;
351 Properties *p = PropOf(TCB);
354 if (p->window_only) {
355 writeRegion.Top = p->SBI.srWindow.Top;
356 writeRegion.Left = p->SBI.srWindow.Left;
357 writeRegion.Bottom = p->SBI.srWindow.Bottom;
358 writeRegion.Right = p->SBI.srWindow.Right;
359 T(("... restoring window"));
362 writeRegion.Left = 0;
363 writeRegion.Bottom = (SHORT) (p->SBI.dwSize.Y - 1);
364 writeRegion.Right = (SHORT) (p->SBI.dwSize.X - 1);
365 T(("... restoring entire buffer"));
368 bufferCoord.X = bufferCoord.Y = 0;
370 if (WriteConsoleOutput(TCB->hdl,
376 mvcur(-1, -1, LINES - 2, 0);
378 T(("... restore original screen contents %s", result ? "ok" : "err"));
383 drv_name(TERMINAL_CONTROL_BLOCK * TCB)
386 return "win32console";
390 drv_doupdate(TERMINAL_CONTROL_BLOCK * TCB)
393 int y, nonempty, n, x0, x1, Width, Height;
399 T((T_CALLED("win32con::drv_doupdate(%p)"), TCB));
400 if (okConsoleHandle(TCB)) {
402 Width = screen_columns(sp);
403 Height = screen_lines(sp);
404 nonempty = min(Height, NewScreen(sp)->_maxy + 1);
406 if ((CurScreen(sp)->_clear || NewScreen(sp)->_clear)) {
408 #if USE_WIDEC_SUPPORT
409 cchar_t empty[Width];
415 for (x = 0; x < Width; x++)
416 setcchar(&empty[x], blank, 0, 0, 0);
420 for (x = 0; x < Width; x++)
424 for (y = 0; y < nonempty; y++) {
425 con_write(TCB, y, 0, empty, Width);
427 CurScreen(sp)->_line[y].text,
428 (size_t) Width * sizeof(empty[0]));
430 CurScreen(sp)->_clear = FALSE;
431 NewScreen(sp)->_clear = FALSE;
432 touchwin(NewScreen(sp));
435 for (y = 0; y < nonempty; y++) {
436 x0 = NewScreen(sp)->_line[y].firstchar;
437 if (x0 != _NOCHANGE) {
440 int limit = NewScreen(sp)->_line[y].lastchar;
441 while ((x1 = EndChange(x0)) <= limit) {
442 while ((x2 = NextChange(x1)) <= limit && x2 <= (x1 + 2)) {
446 memcpy(&CurScreen(sp)->_line[y].text[x0],
447 &NewScreen(sp)->_line[y].text[x0],
448 n * sizeof(CurScreen(sp)->_line[y].text[x0]));
452 &CurScreen(sp)->_line[y].text[x0], n);
456 /* mark line changed successfully */
457 if (y <= NewScreen(sp)->_maxy) {
458 MARK_NOCHANGE(NewScreen(sp), y);
460 if (y <= CurScreen(sp)->_maxy) {
461 MARK_NOCHANGE(CurScreen(sp), y);
464 x1 = NewScreen(sp)->_line[y].lastchar;
467 memcpy(&CurScreen(sp)->_line[y].text[x0],
468 &NewScreen(sp)->_line[y].text[x0],
469 (size_t) n * sizeof(CurScreen(sp)->_line[y].text[x0]));
473 &CurScreen(sp)->_line[y].text[x0], n);
475 /* mark line changed successfully */
476 if (y <= NewScreen(sp)->_maxy) {
477 MARK_NOCHANGE(NewScreen(sp), y);
479 if (y <= CurScreen(sp)->_maxy) {
480 MARK_NOCHANGE(CurScreen(sp), y);
487 /* put everything back in sync */
488 for (y = nonempty; y <= NewScreen(sp)->_maxy; y++) {
489 MARK_NOCHANGE(NewScreen(sp), y);
491 for (y = nonempty; y <= CurScreen(sp)->_maxy; y++) {
492 MARK_NOCHANGE(CurScreen(sp), y);
495 if (!NewScreen(sp)->_leaveok) {
496 CurScreen(sp)->_curx = NewScreen(sp)->_curx;
497 CurScreen(sp)->_cury = NewScreen(sp)->_cury;
499 TCB->drv->td_hwcur(TCB,
501 CurScreen(sp)->_cury, CurScreen(sp)->_curx);
503 selectActiveHandle(TCB);
510 drv_CanHandle(TERMINAL_CONTROL_BLOCK * TCB,
512 int *errret GCC_UNUSED)
516 T((T_CALLED("win32con::drv_CanHandle(%p)"), TCB));
518 assert((TCB != 0) && (tname != 0));
520 TCB->magic = WINMAGIC;
522 if (tname == 0 || *tname == 0)
524 else if (tname != 0 && *tname == '#') {
526 * Use "#" (a character which cannot begin a terminal's name) to
527 * select specific driver from the table.
529 * In principle, we could have more than one non-terminfo driver,
532 size_t n = strlen(tname + 1);
534 && (strncmp(tname + 1, "win32console", n) == 0)) {
537 } else if (tname != 0 && stricmp(tname, "unknown") == 0) {
542 * This is intentional, to avoid unnecessary breakage of applications
543 * using <term.h> symbols.
545 if (code && (TCB->term.type.Booleans == 0)) {
546 _nc_init_termtype(&(TCB->term.type));
552 drv_dobeepflash(TERMINAL_CONTROL_BLOCK * TCB,
553 int beepFlag GCC_UNUSED)
565 drv_print(TERMINAL_CONTROL_BLOCK * TCB,
566 char *data GCC_UNUSED,
578 drv_defaultcolors(TERMINAL_CONTROL_BLOCK * TCB,
592 get_SBI(TERMINAL_CONTROL_BLOCK * TCB)
595 Properties *p = PropOf(TCB);
596 if (GetConsoleScreenBufferInfo(TCB->hdl, &(p->SBI))) {
597 T(("GetConsoleScreenBufferInfo"));
598 T(("... buffer(X:%d Y:%d)",
601 T(("... window(X:%d Y:%d)",
602 p->SBI.dwMaximumWindowSize.X,
603 p->SBI.dwMaximumWindowSize.Y));
604 T(("... cursor(X:%d Y:%d)",
605 p->SBI.dwCursorPosition.X,
606 p->SBI.dwCursorPosition.Y));
607 T(("... display(Top:%d Bottom:%d Left:%d Right:%d)",
609 p->SBI.srWindow.Bottom,
610 p->SBI.srWindow.Left,
611 p->SBI.srWindow.Right));
616 p->origin.X = p->SBI.srWindow.Left;
617 p->origin.Y = p->SBI.srWindow.Top;
621 T(("GetConsoleScreenBufferInfo ERR"));
627 drv_setcolor(TERMINAL_CONTROL_BLOCK * TCB,
630 int (*outc) (SCREEN *, int) GCC_UNUSED)
634 if (okConsoleHandle(TCB) &&
636 WORD a = MapColor(fore, color);
637 a |= (WORD) ((PropOf(TCB)->SBI.wAttributes) & (fore ? 0xfff8 : 0xff8f));
638 SetConsoleTextAttribute(TCB->hdl, a);
644 drv_rescol(TERMINAL_CONTROL_BLOCK * TCB)
649 if (okConsoleHandle(TCB)) {
650 WORD a = FOREGROUND_BLUE | FOREGROUND_RED | FOREGROUND_GREEN;
651 SetConsoleTextAttribute(TCB->hdl, a);
659 drv_rescolors(TERMINAL_CONTROL_BLOCK * TCB)
671 drv_size(TERMINAL_CONTROL_BLOCK * TCB, int *Lines, int *Cols)
677 T((T_CALLED("win32con::drv_size(%p)"), TCB));
679 if (okConsoleHandle(TCB) &&
683 if (PropOf(TCB)->buffered) {
684 *Lines = (int) (PropOf(TCB)->SBI.dwSize.Y);
685 *Cols = (int) (PropOf(TCB)->SBI.dwSize.X);
687 *Lines = (int) (PropOf(TCB)->SBI.srWindow.Bottom + 1 -
688 PropOf(TCB)->SBI.srWindow.Top);
689 *Cols = (int) (PropOf(TCB)->SBI.srWindow.Right + 1 -
690 PropOf(TCB)->SBI.srWindow.Left);
698 drv_setsize(TERMINAL_CONTROL_BLOCK * TCB GCC_UNUSED,
707 drv_sgmode(TERMINAL_CONTROL_BLOCK * TCB, int setFlag, TTY * buf)
715 if (TCB == 0 || buf == NULL)
719 iflag = buf->c_iflag;
720 lflag = buf->c_lflag;
722 GetConsoleMode(TCB->inp, &dwFlag);
725 dwFlag |= ENABLE_LINE_INPUT;
727 dwFlag &= (DWORD) (~ENABLE_LINE_INPUT);
730 dwFlag |= ENABLE_ECHO_INPUT;
732 dwFlag &= (DWORD) (~ENABLE_ECHO_INPUT);
735 dwFlag |= ENABLE_PROCESSED_INPUT;
737 dwFlag &= (DWORD) (~ENABLE_PROCESSED_INPUT);
739 dwFlag |= ENABLE_MOUSE_INPUT;
741 buf->c_iflag = iflag;
742 buf->c_lflag = lflag;
743 SetConsoleMode(TCB->inp, dwFlag);
744 TCB->term.Nttyb = *buf;
746 iflag = TCB->term.Nttyb.c_iflag;
747 lflag = TCB->term.Nttyb.c_lflag;
748 GetConsoleMode(TCB->inp, &dwFlag);
750 if (dwFlag & ENABLE_LINE_INPUT)
753 lflag &= (tcflag_t) (~ICANON);
755 if (dwFlag & ENABLE_ECHO_INPUT)
758 lflag &= (tcflag_t) (~ECHO);
760 if (dwFlag & ENABLE_PROCESSED_INPUT)
763 iflag &= (tcflag_t) (~BRKINT);
765 TCB->term.Nttyb.c_iflag = iflag;
766 TCB->term.Nttyb.c_lflag = lflag;
768 *buf = TCB->term.Nttyb;
774 drv_mode(TERMINAL_CONTROL_BLOCK * TCB, int progFlag, int defFlag)
777 TERMINAL *_term = (TERMINAL *) TCB;
783 T((T_CALLED("win32con::drv_mode(%p, prog=%d, def=%d)"), TCB, progFlag, defFlag));
784 PropOf(TCB)->progMode = progFlag;
785 PropOf(TCB)->lastOut = progFlag ? TCB->hdl : TCB->out;
786 SetConsoleActiveScreenBuffer(PropOf(TCB)->lastOut);
788 if (progFlag) /* prog mode */ {
790 if ((drv_sgmode(TCB, FALSE, &(_term->Nttyb)) == OK)) {
791 _term->Nttyb.c_oflag &= (tcflag_t) (~OFLAGS_TABS);
795 /* reset_prog_mode */
796 if (drv_sgmode(TCB, TRUE, &(_term->Nttyb)) == OK) {
799 _nc_keypad(sp, TRUE);
804 } else { /* shell mode */
807 if (drv_sgmode(TCB, FALSE, &(_term->Ottyb)) == OK) {
811 /* reset_shell_mode */
813 _nc_keypad(sp, FALSE);
814 NCURSES_SP_NAME(_nc_flush) (sp);
816 code = drv_sgmode(TCB, TRUE, &(_term->Ottyb));
817 if (!PropOf(TCB)->buffered) {
818 if (!restore_original_screen(TCB))
828 drv_screen_init(SCREEN *sp GCC_UNUSED)
833 drv_wrap(SCREEN *sp GCC_UNUSED)
838 rkeycompare(const void *el1, const void *el2)
840 WORD key1 = (LOWORD((*((const LONG *) el1)))) & 0x7fff;
841 WORD key2 = (LOWORD((*((const LONG *) el2)))) & 0x7fff;
843 return ((key1 < key2) ? -1 : ((key1 == key2) ? 0 : 1));
847 keycompare(const void *el1, const void *el2)
849 WORD key1 = HIWORD((*((const LONG *) el1)));
850 WORD key2 = HIWORD((*((const LONG *) el2)));
852 return ((key1 < key2) ? -1 : ((key1 == key2) ? 0 : 1));
856 MapKey(TERMINAL_CONTROL_BLOCK * TCB, WORD vKey)
860 LONG key = GenMap(vKey, 0);
867 (size_t) (N_INI + FKEYS),
871 key = *((LONG *) res);
873 code = (int) (nKey & 0x7fff);
881 drv_release(TERMINAL_CONTROL_BLOCK * TCB)
883 T((T_CALLED("win32con::drv_release(%p)"), TCB));
893 * Attempt to save the screen contents. PDCurses does this if
894 * PDC_RESTORE_SCREEN is set, giving the same visual appearance on restoration
895 * as if the library had allocated a console buffer.
898 save_original_screen(TERMINAL_CONTROL_BLOCK * TCB)
901 Properties *p = PropOf(TCB);
904 SMALL_RECT readRegion;
907 bufferSize.X = p->SBI.dwSize.X;
908 bufferSize.Y = p->SBI.dwSize.Y;
909 want = (size_t) (bufferSize.X * bufferSize.Y);
911 if ((p->save_screen = malloc(want * sizeof(CHAR_INFO))) != 0) {
912 bufferCoord.X = bufferCoord.Y = 0;
916 readRegion.Bottom = (SHORT) (bufferSize.Y - 1);
917 readRegion.Right = (SHORT) (bufferSize.X - 1);
919 T(("... reading console buffer %dx%d into %d,%d - %d,%d at %d,%d",
920 bufferSize.Y, bufferSize.X,
928 if (ReadConsoleOutput(TCB->hdl,
935 T((" error %#lx", (unsigned long) GetLastError()));
936 FreeAndNull(p->save_screen);
938 bufferSize.X = (SHORT) (p->SBI.srWindow.Right
939 - p->SBI.srWindow.Left + 1);
940 bufferSize.Y = (SHORT) (p->SBI.srWindow.Bottom
941 - p->SBI.srWindow.Top + 1);
942 want = (size_t) (bufferSize.X * bufferSize.Y);
944 if ((p->save_screen = malloc(want * sizeof(CHAR_INFO))) != 0) {
945 bufferCoord.X = bufferCoord.Y = 0;
947 readRegion.Top = p->SBI.srWindow.Top;
948 readRegion.Left = p->SBI.srWindow.Left;
949 readRegion.Bottom = p->SBI.srWindow.Bottom;
950 readRegion.Right = p->SBI.srWindow.Right;
952 T(("... reading console window %dx%d into %d,%d - %d,%d at %d,%d",
953 bufferSize.Y, bufferSize.X,
961 if (ReadConsoleOutput(TCB->hdl,
967 p->window_only = TRUE;
969 T((" error %#lx", (unsigned long) GetLastError()));
975 T(("... save original screen contents %s", result ? "ok" : "err"));
980 drv_init(TERMINAL_CONTROL_BLOCK * TCB)
984 T((T_CALLED("win32con::drv_init(%p)"), TCB));
989 BOOL b = AllocConsole();
992 bool buffered = TRUE;
995 b = AttachConsole(ATTACH_PARENT_PROCESS);
997 TCB->inp = GetStdHandle(STD_INPUT_HANDLE);
998 TCB->out = GetStdHandle(STD_OUTPUT_HANDLE);
1000 if (getenv("NCGDB") || getenv("NCURSES_CONSOLE2")) {
1001 TCB->hdl = TCB->out;
1004 TCB->hdl = CreateConsoleScreenBuffer(GENERIC_READ | GENERIC_WRITE,
1007 CONSOLE_TEXTMODE_BUFFER,
1011 if (InvalidConsoleHandle(TCB->hdl)) {
1013 } else if ((TCB->prop = typeCalloc(Properties, 1)) != 0) {
1014 PropOf(TCB)->buffered = buffered;
1015 PropOf(TCB)->window_only = FALSE;
1016 if (!get_SBI(TCB)) {
1017 FreeAndNull(TCB->prop); /* force error in drv_size */
1021 if (!save_original_screen(TCB)) {
1022 FreeAndNull(TCB->prop); /* force error in drv_size */
1028 TCB->info.initcolor = TRUE;
1029 TCB->info.canchange = FALSE;
1030 TCB->info.hascolor = TRUE;
1031 TCB->info.caninit = TRUE;
1033 TCB->info.maxpairs = NUMPAIRS;
1034 TCB->info.maxcolors = 8;
1035 TCB->info.numlabels = 0;
1036 TCB->info.labelwidth = 0;
1037 TCB->info.labelheight = 0;
1038 TCB->info.nocolorvideo = 1;
1039 TCB->info.tabsize = 8;
1041 if (GetNumberOfConsoleMouseButtons(&num_buttons)) {
1042 T(("mouse has %ld buttons", num_buttons));
1043 TCB->info.numbuttons = (int) num_buttons;
1045 TCB->info.numbuttons = 1;
1048 TCB->info.defaultPalette = _nc_cga_palette;
1050 for (i = 0; i < (N_INI + FKEYS); i++) {
1052 PropOf(TCB)->rmap[i] = PropOf(TCB)->map[i] = (DWORD) keylist[i];
1054 PropOf(TCB)->rmap[i] = PropOf(TCB)->map[i] =
1055 (DWORD) GenMap((VK_F1 + (i - N_INI)), (KEY_F(1) + (i - N_INI)));
1057 qsort(PropOf(TCB)->map,
1061 qsort(PropOf(TCB)->rmap,
1066 a = MapColor(true, COLOR_WHITE) | MapColor(false, COLOR_BLACK);
1067 for (i = 0; i < NUMPAIRS; i++)
1068 PropOf(TCB)->pairs[i] = a;
1074 drv_initpair(TERMINAL_CONTROL_BLOCK * TCB,
1084 if ((pair > 0) && (pair < NUMPAIRS) && (f >= 0) && (f < 8)
1085 && (b >= 0) && (b < 8)) {
1086 PropOf(TCB)->pairs[pair] = MapColor(true, f) | MapColor(false, b);
1091 drv_initcolor(TERMINAL_CONTROL_BLOCK * TCB,
1092 int color GCC_UNUSED,
1104 drv_do_color(TERMINAL_CONTROL_BLOCK * TCB,
1105 int old_pair GCC_UNUSED,
1106 int pair GCC_UNUSED,
1107 int reverse GCC_UNUSED,
1108 int (*outc) (SCREEN *, int) GCC_UNUSED
1118 drv_initmouse(TERMINAL_CONTROL_BLOCK * TCB)
1125 sp->_mouse_type = M_TERM_DRIVER;
1129 drv_testmouse(TERMINAL_CONTROL_BLOCK * TCB, int delay)
1137 if (sp->_drv_mouse_head < sp->_drv_mouse_tail) {
1140 rc = TCBOf(sp)->drv->td_twait(TCBOf(sp),
1144 EVENTLIST_2nd(evl));
1151 drv_mvcur(TERMINAL_CONTROL_BLOCK * TCB,
1152 int yold GCC_UNUSED, int xold GCC_UNUSED,
1156 if (okConsoleHandle(TCB)) {
1157 Properties *p = PropOf(TCB);
1160 loc.Y = (short) (y + AdjustY(p));
1161 SetConsoleCursorPosition(TCB->hdl, loc);
1168 drv_hwlabel(TERMINAL_CONTROL_BLOCK * TCB,
1169 int labnum GCC_UNUSED,
1170 char *text GCC_UNUSED)
1179 drv_hwlabelOnOff(TERMINAL_CONTROL_BLOCK * TCB,
1180 int OnFlag GCC_UNUSED)
1189 drv_conattr(TERMINAL_CONTROL_BLOCK * TCB GCC_UNUSED)
1191 chtype res = A_NORMAL;
1192 res |= (A_BOLD | A_DIM | A_REVERSE | A_STANDOUT | A_COLOR);
1197 drv_setfilter(TERMINAL_CONTROL_BLOCK * TCB)
1206 drv_initacs(TERMINAL_CONTROL_BLOCK * TCB,
1207 chtype *real_map GCC_UNUSED,
1208 chtype *fake_map GCC_UNUSED)
1210 #define DATA(a,b) { a, b }
1215 DATA('a', 0xb1), /* ACS_CKBOARD */
1216 DATA('f', 0xf8), /* ACS_DEGREE */
1217 DATA('g', 0xf1), /* ACS_PLMINUS */
1218 DATA('j', 0xd9), /* ACS_LRCORNER */
1219 DATA('l', 0xda), /* ACS_ULCORNER */
1220 DATA('k', 0xbf), /* ACS_URCORNER */
1221 DATA('m', 0xc0), /* ACS_LLCORNER */
1222 DATA('n', 0xc5), /* ACS_PLUS */
1223 DATA('q', 0xc4), /* ACS_HLINE */
1224 DATA('t', 0xc3), /* ACS_LTEE */
1225 DATA('u', 0xb4), /* ACS_RTEE */
1226 DATA('v', 0xc1), /* ACS_BTEE */
1227 DATA('w', 0xc2), /* ACS_TTEE */
1228 DATA('x', 0xb3), /* ACS_VLINE */
1229 DATA('y', 0xf3), /* ACS_LEQUAL */
1230 DATA('z', 0xf2), /* ACS_GEQUAL */
1231 DATA('0', 0xdb), /* ACS_BLOCK */
1232 DATA('{', 0xe3), /* ACS_PI */
1233 DATA('}', 0x9c), /* ACS_STERLING */
1234 DATA(',', 0xae), /* ACS_LARROW */
1235 DATA('+', 0xaf), /* ACS_RARROW */
1236 DATA('~', 0xf9), /* ACS_BULLET */
1245 for (n = 0; n < SIZEOF(table); ++n) {
1246 real_map[table[n].acs_code] = (chtype) table[n].use_code | A_ALTCHARSET;
1248 sp->_screen_acs_map[table[n].acs_code] = TRUE;
1253 tdiff(FILETIME fstart, FILETIME fend)
1255 ULARGE_INTEGER ustart;
1256 ULARGE_INTEGER uend;
1259 ustart.LowPart = fstart.dwLowDateTime;
1260 ustart.HighPart = fstart.dwHighDateTime;
1261 uend.LowPart = fend.dwLowDateTime;
1262 uend.HighPart = fend.dwHighDateTime;
1264 diff = (uend.QuadPart - ustart.QuadPart) / 10000;
1269 Adjust(int milliseconds, int diff)
1271 if (milliseconds == INFINITY)
1272 return milliseconds;
1273 milliseconds -= diff;
1274 if (milliseconds < 0)
1276 return milliseconds;
1279 #define BUTTON_MASK (FROM_LEFT_1ST_BUTTON_PRESSED | \
1280 FROM_LEFT_2ND_BUTTON_PRESSED | \
1281 FROM_LEFT_3RD_BUTTON_PRESSED | \
1282 FROM_LEFT_4TH_BUTTON_PRESSED | \
1283 RIGHTMOST_BUTTON_PRESSED)
1286 decode_mouse(TERMINAL_CONTROL_BLOCK * TCB, int mask)
1294 if (mask & FROM_LEFT_1ST_BUTTON_PRESSED)
1295 result |= BUTTON1_PRESSED;
1296 if (mask & FROM_LEFT_2ND_BUTTON_PRESSED)
1297 result |= BUTTON2_PRESSED;
1298 if (mask & FROM_LEFT_3RD_BUTTON_PRESSED)
1299 result |= BUTTON3_PRESSED;
1300 if (mask & FROM_LEFT_4TH_BUTTON_PRESSED)
1301 result |= BUTTON4_PRESSED;
1303 if (mask & RIGHTMOST_BUTTON_PRESSED) {
1304 switch (TCB->info.numbuttons) {
1306 result |= BUTTON1_PRESSED;
1309 result |= BUTTON2_PRESSED;
1312 result |= BUTTON3_PRESSED;
1315 result |= BUTTON4_PRESSED;
1324 drv_twait(TERMINAL_CONTROL_BLOCK * TCB,
1328 EVENTLIST_2nd(_nc_eventlist * evl))
1331 INPUT_RECORD inp_rec;
1333 DWORD nRead = 0, rc = (DWORD) (-1);
1338 bool isImmed = (milliseconds == 0);
1340 #define CONSUME() ReadConsoleInput(TCB->inp,&inp_rec,1,&nRead)
1345 TR(TRACE_IEVENT, ("start twait: %d milliseconds, mode: %d",
1346 milliseconds, mode));
1348 if (milliseconds < 0)
1349 milliseconds = INFINITY;
1351 memset(&inp_rec, 0, sizeof(inp_rec));
1354 GetSystemTimeAsFileTime(&fstart);
1355 rc = WaitForSingleObject(TCB->inp, (DWORD) milliseconds);
1356 GetSystemTimeAsFileTime(&fend);
1357 diff = (int) tdiff(fstart, fend);
1358 milliseconds = Adjust(milliseconds, diff);
1360 if (!isImmed && milliseconds == 0)
1363 if (rc == WAIT_OBJECT_0) {
1365 b = GetNumberOfConsoleInputEvents(TCB->inp, &nRead);
1366 if (b && nRead > 0) {
1367 b = PeekConsoleInput(TCB->inp, &inp_rec, 1, &nRead);
1368 if (b && nRead > 0) {
1369 switch (inp_rec.EventType) {
1371 if (mode & TW_INPUT) {
1372 WORD vk = inp_rec.Event.KeyEvent.wVirtualKeyCode;
1373 char ch = inp_rec.Event.KeyEvent.uChar.AsciiChar;
1375 if (inp_rec.Event.KeyEvent.bKeyDown) {
1377 int nKey = MapKey(TCB, vk);
1378 if ((nKey < 0) || FALSE == sp->_keypad_on) {
1391 if (decode_mouse(TCB,
1392 (inp_rec.Event.MouseEvent.dwButtonState
1393 & BUTTON_MASK)) == 0) {
1395 } else if (mode & TW_MOUSE) {
1401 selectActiveHandle(TCB);
1409 if (rc != WAIT_TIMEOUT) {
1420 TR(TRACE_IEVENT, ("end twait: returned %d (%d), remaining time %d msec",
1421 code, errno, milliseconds));
1424 *timeleft = milliseconds;
1430 handle_mouse(TERMINAL_CONTROL_BLOCK * TCB, MOUSE_EVENT_RECORD mer)
1434 bool result = FALSE;
1439 sp->_drv_mouse_old_buttons = sp->_drv_mouse_new_buttons;
1440 sp->_drv_mouse_new_buttons = mer.dwButtonState & BUTTON_MASK;
1443 * We're only interested if the button is pressed or released.
1444 * FIXME: implement continuous event-tracking.
1446 if (sp->_drv_mouse_new_buttons != sp->_drv_mouse_old_buttons) {
1447 Properties *p = PropOf(TCB);
1449 memset(&work, 0, sizeof(work));
1451 if (sp->_drv_mouse_new_buttons) {
1453 work.bstate |= (mmask_t) decode_mouse(TCB, sp->_drv_mouse_new_buttons);
1457 /* cf: BUTTON_PRESSED, BUTTON_RELEASED */
1458 work.bstate |= (mmask_t) (decode_mouse(TCB,
1459 sp->_drv_mouse_old_buttons)
1465 work.x = mer.dwMousePosition.X;
1466 work.y = mer.dwMousePosition.Y - AdjustY(p);
1468 sp->_drv_mouse_fifo[sp->_drv_mouse_tail] = work;
1469 sp->_drv_mouse_tail += 1;
1476 drv_read(TERMINAL_CONTROL_BLOCK * TCB, int *buf)
1480 INPUT_RECORD inp_rec;
1489 memset(&inp_rec, 0, sizeof(inp_rec));
1491 T((T_CALLED("win32con::drv_read(%p)"), TCB));
1492 while ((b = ReadConsoleInput(TCB->inp, &inp_rec, 1, &nRead))) {
1493 if (b && nRead > 0) {
1494 if (inp_rec.EventType == KEY_EVENT) {
1495 if (!inp_rec.Event.KeyEvent.bKeyDown)
1497 *buf = (int) inp_rec.Event.KeyEvent.uChar.AsciiChar;
1498 vk = inp_rec.Event.KeyEvent.wVirtualKeyCode;
1500 if (sp->_keypad_on) {
1501 *buf = MapKey(TCB, vk);
1508 } else { /* *buf != 0 */
1511 } else if (inp_rec.EventType == MOUSE_EVENT) {
1512 if (handle_mouse(TCB, inp_rec.Event.MouseEvent)) {
1524 drv_nap(TERMINAL_CONTROL_BLOCK * TCB GCC_UNUSED, int ms)
1526 T((T_CALLED("win32con::drv_nap(%p, %d)"), TCB, ms));
1532 drv_kyExist(TERMINAL_CONTROL_BLOCK * TCB, int keycode)
1538 LONG key = GenMap(0, (WORD) keycode);
1545 T((T_CALLED("win32con::drv_kyExist(%p, %d)"), TCB, keycode));
1548 (size_t) (N_INI + FKEYS),
1552 key = *((LONG *) res);
1554 if (!(nKey & 0x8000))
1561 drv_kpad(TERMINAL_CONTROL_BLOCK * TCB, int flag GCC_UNUSED)
1569 T((T_CALLED("win32con::drv_kpad(%p, %d)"), TCB, flag));
1577 drv_keyok(TERMINAL_CONTROL_BLOCK * TCB, int keycode, int flag)
1584 LONG key = GenMap(0, (WORD) keycode);
1589 T((T_CALLED("win32con::drv_keyok(%p, %d, %d)"), TCB, keycode, flag));
1593 (size_t) (N_INI + FKEYS),
1597 key = *((LONG *) res);
1599 nKey = (LOWORD(key)) & 0x7fff;
1602 *(LONG *) res = GenMap(vKey, nKey);
1608 NCURSES_EXPORT_VAR (TERM_DRIVER) _nc_WIN_DRIVER = {
1610 drv_name, /* Name */
1611 drv_CanHandle, /* CanHandle */
1612 drv_init, /* init */
1613 drv_release, /* release */
1614 drv_size, /* size */
1615 drv_sgmode, /* sgmode */
1616 drv_conattr, /* conattr */
1617 drv_mvcur, /* hwcur */
1618 drv_mode, /* mode */
1619 drv_rescol, /* rescol */
1620 drv_rescolors, /* rescolors */
1621 drv_setcolor, /* color */
1622 drv_dobeepflash, /* DoBeepFlash */
1623 drv_initpair, /* initpair */
1624 drv_initcolor, /* initcolor */
1625 drv_do_color, /* docolor */
1626 drv_initmouse, /* initmouse */
1627 drv_testmouse, /* testmouse */
1628 drv_setfilter, /* setfilter */
1629 drv_hwlabel, /* hwlabel */
1630 drv_hwlabelOnOff, /* hwlabelOnOff */
1631 drv_doupdate, /* update */
1632 drv_defaultcolors, /* defaultcolors */
1633 drv_print, /* print */
1634 drv_size, /* getsize */
1635 drv_setsize, /* setsize */
1636 drv_initacs, /* initacs */
1637 drv_screen_init, /* scinit */
1638 drv_wrap, /* scexit */
1639 drv_twait, /* twait */
1640 drv_read, /* read */
1642 drv_kpad, /* kpad */
1643 drv_keyok, /* kyOk */
1644 drv_kyExist /* kyExist */