summaryrefslogtreecommitdiff
path: root/ncurses/win32con/win_driver.c
diff options
context:
space:
mode:
Diffstat (limited to 'ncurses/win32con/win_driver.c')
-rw-r--r--ncurses/win32con/win_driver.c1784
1 files changed, 1386 insertions, 398 deletions
diff --git a/ncurses/win32con/win_driver.c b/ncurses/win32con/win_driver.c
index c214639..7478ace 100644
--- a/ncurses/win32con/win_driver.c
+++ b/ncurses/win32con/win_driver.c
@@ -1,5 +1,5 @@
/****************************************************************************
- * Copyright (c) 1998-2009,2010 Free Software Foundation, Inc. *
+ * Copyright (c) 1998-2014,2015 Free Software Foundation, Inc. *
* *
* Permission is hereby granted, free of charge, to any person obtaining a *
* copy of this software and associated documentation files (the *
@@ -28,26 +28,61 @@
/****************************************************************************
* Author: Juergen Pfeifer *
- * *
+ * and: Thomas E. Dickey *
****************************************************************************/
/*
* TODO - GetMousePos(POINT * result) from ntconio.c
* TODO - implement nodelay
+ * TODO - improve screen-repainting performance, using implied wraparound to reduce write's
+ * TODO - make it optional whether screen is restored or not when non-buffered
*/
#include <curses.priv.h>
+
+#ifdef __MINGW32__
+#include <tchar.h>
+#else
+#include <windows.h>
+#include <wchar.h>
+#endif
+
+#include <io.h>
+
+#define PSAPI_VERSION 2
+#include <psapi.h>
+
#define CUR my_term.type.
-MODULE_ID("$Id: win_driver.c,v 1.10 2010/12/25 19:28:21 tom Exp $")
+MODULE_ID("$Id: win_driver.c,v 1.54 2015/01/10 23:13:24 tom Exp $")
+
+#ifndef __GNUC__
+# error We need GCC to compile for MinGW
+#endif
#define WINMAGIC NCDRV_MAGIC(NCDRV_WINCONSOLE)
-#define AssertTCB() assert(TCB!=0 && TCB->magic==WINMAGIC)
-#define SetSP() assert(TCB->csp!=0); sp = TCB->csp
+#define EXP_OPTIMIZE 0
+
+#define array_length(a) (sizeof(a)/sizeof(a[0]))
+
+#define okConsoleHandle(TCB) (TCB != 0 && CON.hdl != INVALID_HANDLE_VALUE)
+
+#define AssertTCB() assert(TCB != 0 && (TCB->magic == WINMAGIC))
+#define SetSP() assert(TCB->csp != 0); sp = TCB->csp; (void) sp
#define GenMap(vKey,key) MAKELONG(key, vKey)
+#define AdjustY() (CON.buffered ? 0 : (int) CON.SBI.srWindow.Top)
+
+#if USE_WIDEC_SUPPORT
+#define write_screen WriteConsoleOutputW
+#define read_screen ReadConsoleOutputW
+#else
+#define write_screen WriteConsoleOutput
+#define read_screen ReadConsoleOutput
+#endif
+
static const LONG keylist[] =
{
GenMap(VK_PRIOR, KEY_PPAGE),
@@ -61,31 +96,54 @@ static const LONG keylist[] =
GenMap(VK_DELETE, KEY_DC),
GenMap(VK_INSERT, KEY_IC)
};
-#define N_INI ((int)(sizeof(keylist)/sizeof(keylist[0])))
+static const LONG ansi_keys[] =
+{
+ GenMap(VK_PRIOR, 'I'),
+ GenMap(VK_NEXT, 'Q'),
+ GenMap(VK_END, 'O'),
+ GenMap(VK_HOME, 'H'),
+ GenMap(VK_LEFT, 'K'),
+ GenMap(VK_UP, 'H'),
+ GenMap(VK_RIGHT, 'M'),
+ GenMap(VK_DOWN, 'P'),
+ GenMap(VK_DELETE, 'S'),
+ GenMap(VK_INSERT, 'R')
+};
+#define N_INI ((int)array_length(keylist))
#define FKEYS 24
#define MAPSIZE (FKEYS + N_INI)
#define NUMPAIRS 64
-typedef struct props {
- CONSOLE_SCREEN_BUFFER_INFO SBI;
- bool progMode;
+/* A process can only have a single console, so it's safe
+ to maintain all the information about it in a single
+ static structure.
+ */
+static struct {
+ BOOL initialized;
+ BOOL buffered;
+ BOOL window_only;
+ BOOL progMode;
+ BOOL isMinTTY;
+ BOOL isTermInfoConsole;
+ HANDLE out;
+ HANDLE inp;
+ HANDLE hdl;
+ HANDLE lastOut;
+ int numButtons;
+ DWORD ansi_map[MAPSIZE];
DWORD map[MAPSIZE];
DWORD rmap[MAPSIZE];
WORD pairs[NUMPAIRS];
-} Properties;
-
-#define PropOf(TCB) ((Properties*)TCB->prop)
+ COORD origin;
+ CHAR_INFO *save_screen;
+ COORD save_size;
+ SMALL_RECT save_region;
+ CONSOLE_SCREEN_BUFFER_INFO SBI;
+ CONSOLE_SCREEN_BUFFER_INFO save_SBI;
+ CONSOLE_CURSOR_INFO save_CI;
+} CON;
-int
-_nc_mingw_ioctl(int fd GCC_UNUSED,
- long int request GCC_UNUSED,
- struct termios *arg GCC_UNUSED)
-{
- return 0;
- endwin();
- fprintf(stderr, "TERMINFO currently not supported on Windows.\n");
- exit(1);
-}
+static BOOL console_initialized = FALSE;
static WORD
MapColor(bool fore, int color)
@@ -102,29 +160,32 @@ MapColor(bool fore, int color)
return (WORD) a;
}
+#define RevAttr(attr) \
+ (WORD) (((attr) & 0xff00) | \
+ ((((attr) & 0x07) << 4) | \
+ (((attr) & 0x70) >> 4)))
+
static WORD
-MapAttr(TERMINAL_CONTROL_BLOCK * TCB, WORD res, chtype ch)
+MapAttr(WORD res, attr_t ch)
{
if (ch & A_COLOR) {
int p;
- SCREEN *sp;
- AssertTCB();
- SetSP();
p = PairNumber(ch);
- if (p > 0 && p < NUMPAIRS && TCB != 0 && sp != 0) {
+ if (p > 0 && p < NUMPAIRS) {
WORD a;
- a = PropOf(TCB)->pairs[p];
- res = (res & 0xff00) | a;
+ a = CON.pairs[p];
+ res = (WORD) ((res & 0xff00) | a);
}
}
- if (ch & A_REVERSE)
- res = ((res & 0xff00) | (((res & 0x07) << 4) | ((res & 0x70) >> 4)));
+ if (ch & A_REVERSE) {
+ res = RevAttr(res);
+ }
- if (ch & A_STANDOUT)
- res = ((res & 0xff00) | (((res & 0x07) << 4) | ((res & 0x70) >> 4))
- | BACKGROUND_INTENSITY);
+ if (ch & A_STANDOUT) {
+ res = RevAttr(res) | BACKGROUND_INTENSITY;
+ }
if (ch & A_BOLD)
res |= FOREGROUND_INTENSITY;
@@ -135,33 +196,138 @@ MapAttr(TERMINAL_CONTROL_BLOCK * TCB, WORD res, chtype ch)
return res;
}
+#if 0 /* def TRACE */
+static void
+dump_screen(const char *fn, int ln)
+{
+ int max_cells = (CON.SBI.dwSize.Y * (1 + CON.SBI.dwSize.X)) + 1;
+ char output[max_cells];
+ CHAR_INFO save_screen[max_cells];
+ COORD save_size;
+ SMALL_RECT save_region;
+ COORD bufferCoord;
+
+ T(("dump_screen %s@%d", fn, ln));
+
+ save_region.Top = CON.SBI.srWindow.Top;
+ save_region.Left = CON.SBI.srWindow.Left;
+ save_region.Bottom = CON.SBI.srWindow.Bottom;
+ save_region.Right = CON.SBI.srWindow.Right;
+
+ save_size.X = (SHORT) (save_region.Right - save_region.Left + 1);
+ save_size.Y = (SHORT) (save_region.Bottom - save_region.Top + 1);
+
+ bufferCoord.X = bufferCoord.Y = 0;
+
+ if (read_screen(CON.hdl,
+ save_screen,
+ save_size,
+ bufferCoord,
+ &save_region)) {
+ int i, j;
+ int ij = 0;
+ int k = 0;
+
+ for (i = save_region.Top; i <= save_region.Bottom; ++i) {
+ for (j = save_region.Left; j <= save_region.Right; ++j) {
+ output[k++] = save_screen[ij++].Char.AsciiChar;
+ }
+ output[k++] = '\n';
+ }
+ output[k] = 0;
+
+ T(("DUMP: %d,%d - %d,%d",
+ save_region.Top,
+ save_region.Left,
+ save_region.Bottom,
+ save_region.Right));
+ T(("%s", output));
+ }
+}
+
+#else
+#define dump_screen(fn,ln) /* nothing */
+#endif
+
+#if USE_WIDEC_SUPPORT
+/*
+ * TODO: support surrogate pairs
+ * TODO: support combining characters
+ * TODO: support acsc
+ * TODO: _nc_wacs should be part of sp.
+ */
static BOOL
-con_write(TERMINAL_CONTROL_BLOCK * TCB, int y, int x, chtype *str, int n)
+con_write16(TERMINAL_CONTROL_BLOCK * TCB, int y, int x, cchar_t *str, int limit)
{
- CHAR_INFO ci[n];
+ int actual = 0;
+ CHAR_INFO ci[limit];
COORD loc, siz;
SMALL_RECT rec;
int i;
- chtype ch;
+ cchar_t ch;
SCREEN *sp;
AssertTCB();
+ SetSP();
+
+ for (i = actual = 0; i < limit; i++) {
+ ch = str[i];
+ if (isWidecExt(ch))
+ continue;
+ ci[actual].Char.UnicodeChar = CharOf(ch);
+ ci[actual].Attributes = MapAttr(CON.SBI.wAttributes,
+ AttrOf(ch));
+ if (AttrOf(ch) & A_ALTCHARSET) {
+ if (_nc_wacs) {
+ int which = CharOf(ch);
+ if (which > 0
+ && which < ACS_LEN
+ && CharOf(_nc_wacs[which]) != 0) {
+ ci[actual].Char.UnicodeChar = CharOf(_nc_wacs[which]);
+ } else {
+ ci[actual].Char.UnicodeChar = ' ';
+ }
+ }
+ }
+ ++actual;
+ }
+
+ loc.X = (SHORT) 0;
+ loc.Y = (SHORT) 0;
+ siz.X = (SHORT) actual;
+ siz.Y = 1;
- if (TCB == 0 || InvalidConsoleHandle(TCB->hdl))
- return FALSE;
+ rec.Left = (SHORT) x;
+ rec.Top = (SHORT) (y + AdjustY());
+ rec.Right = (SHORT) (x + limit - 1);
+ rec.Bottom = rec.Top;
+
+ return write_screen(CON.hdl, ci, siz, loc, &rec);
+}
+#define con_write(tcb, y, x, str, n) con_write16(tcb, y, x, str, n)
+#else
+static BOOL
+con_write8(TERMINAL_CONTROL_BLOCK * TCB, int y, int x, chtype *str, int n)
+{
+ CHAR_INFO ci[n];
+ COORD loc, siz;
+ SMALL_RECT rec;
+ int i;
+ chtype ch;
+ SCREEN *sp;
+ AssertTCB();
SetSP();
for (i = 0; i < n; i++) {
ch = str[i];
ci[i].Char.AsciiChar = ChCharOf(ch);
- ci[i].Attributes = MapAttr(TCB,
- PropOf(TCB)->SBI.wAttributes,
+ ci[i].Attributes = MapAttr(CON.SBI.wAttributes,
ChAttrOf(ch));
if (ChAttrOf(ch) & A_ALTCHARSET) {
if (sp->_acs_map)
ci[i].Char.AsciiChar =
- ChCharOf(NCURSES_SP_NAME(_nc_acs_char) (sp, ChCharOf(ch)));
+ ChCharOf(NCURSES_SP_NAME(_nc_acs_char) (sp, ChCharOf(ch)));
}
}
@@ -175,57 +341,223 @@ con_write(TERMINAL_CONTROL_BLOCK * TCB, int y, int x, chtype *str, int n)
rec.Right = (short) (x + n - 1);
rec.Bottom = rec.Top;
- return WriteConsoleOutput(TCB->hdl, ci, siz, loc, &rec);
+ return write_screen(CON.hdl, ci, siz, loc, &rec);
+}
+#define con_write(tcb, y, x, str, n) con_write8(tcb, y, x, str, n)
+#endif
+
+#if EXP_OPTIMIZE
+/*
+ * Comparing new/current screens, determine the last column-index for a change
+ * beginning on the given row,col position. Unlike a serial terminal, there is
+ * no cost for "moving" the "cursor" on the line as we update it.
+ */
+static int
+find_end_of_change(SCREEN *sp, int row, int col)
+{
+ int result = col;
+ struct ldat *curdat = CurScreen(sp)->_line + row;
+ struct ldat *newdat = NewScreen(sp)->_line + row;
+
+ while (col <= newdat->lastchar) {
+#if USE_WIDEC_SUPPORT
+ if (isWidecExt(curdat->text[col]) || isWidecExt(newdat->text[col])) {
+ result = col;
+ } else if (memcmp(&curdat->text[col],
+ &newdat->text[col],
+ sizeof(curdat->text[0]))) {
+ result = col;
+ } else {
+ break;
+ }
+#else
+ if (curdat->text[col] != newdat->text[col]) {
+ result = col;
+ } else {
+ break;
+ }
+#endif
+ ++col;
+ }
+ return result;
+}
+
+/*
+ * Given a row,col position at the end of a change-chunk, look for the
+ * beginning of the next change-chunk.
+ */
+static int
+find_next_change(SCREEN *sp, int row, int col)
+{
+ struct ldat *curdat = CurScreen(sp)->_line + row;
+ struct ldat *newdat = NewScreen(sp)->_line + row;
+ int result = newdat->lastchar + 1;
+
+ while (++col <= newdat->lastchar) {
+#if USE_WIDEC_SUPPORT
+ if (isWidecExt(curdat->text[col]) != isWidecExt(newdat->text[col])) {
+ result = col;
+ break;
+ } else if (memcmp(&curdat->text[col],
+ &newdat->text[col],
+ sizeof(curdat->text[0]))) {
+ result = col;
+ break;
+ }
+#else
+ if (curdat->text[col] != newdat->text[col]) {
+ result = col;
+ break;
+ }
+#endif
+ }
+ return result;
}
+#define EndChange(first) \
+ find_end_of_change(sp, y, first)
+#define NextChange(last) \
+ find_next_change(sp, y, last)
+
+#endif /* EXP_OPTIMIZE */
+
#define MARK_NOCHANGE(win,row) \
win->_line[row].firstchar = _NOCHANGE; \
win->_line[row].lastchar = _NOCHANGE
+static void
+selectActiveHandle(void)
+{
+ if (CON.lastOut != CON.hdl) {
+ CON.lastOut = CON.hdl;
+ SetConsoleActiveScreenBuffer(CON.lastOut);
+ }
+}
+
+static bool
+restore_original_screen(void)
+{
+ COORD bufferCoord;
+ bool result = FALSE;
+ SMALL_RECT save_region = CON.save_region;
+
+ T(("... restoring %s", CON.window_only ? "window" : "entire buffer"));
+
+ bufferCoord.X = (SHORT) (CON.window_only ? CON.SBI.srWindow.Left : 0);
+ bufferCoord.Y = (SHORT) (CON.window_only ? CON.SBI.srWindow.Top : 0);
+
+ if (write_screen(CON.hdl,
+ CON.save_screen,
+ CON.save_size,
+ bufferCoord,
+ &save_region)) {
+ result = TRUE;
+ mvcur(-1, -1, LINES - 2, 0);
+ T(("... restore original screen contents ok %dx%d (%d,%d - %d,%d)",
+ CON.save_size.Y,
+ CON.save_size.X,
+ save_region.Top,
+ save_region.Left,
+ save_region.Bottom,
+ save_region.Right));
+ } else {
+ T(("... restore original screen contents err"));
+ }
+ return result;
+}
+
+static const char *
+wcon_name(TERMINAL_CONTROL_BLOCK * TCB)
+{
+ (void) TCB;
+ return "win32console";
+}
+
static int
-drv_doupdate(TERMINAL_CONTROL_BLOCK * TCB)
+wcon_doupdate(TERMINAL_CONTROL_BLOCK * TCB)
{
+ int result = ERR;
int y, nonempty, n, x0, x1, Width, Height;
SCREEN *sp;
AssertTCB();
SetSP();
- Width = screen_columns(sp);
- Height = screen_lines(sp);
- nonempty = min(Height, NewScreen(sp)->_maxy + 1);
+ T((T_CALLED("win32con::wcon_doupdate(%p)"), TCB));
+ if (okConsoleHandle(TCB)) {
- if ((CurScreen(sp)->_clear || NewScreen(sp)->_clear)) {
- int x;
- chtype empty[Width];
+ Width = screen_columns(sp);
+ Height = screen_lines(sp);
+ nonempty = min(Height, NewScreen(sp)->_maxy + 1);
- for (x = 0; x < Width; x++)
- empty[x] = ' ';
+ T(("... %dx%d clear cur:%d new:%d",
+ Height, Width,
+ CurScreen(sp)->_clear,
+ NewScreen(sp)->_clear));
- for (y = 0; y < nonempty; y++) {
- con_write(TCB, y, 0, empty, Width);
- memcpy(empty,
- CurScreen(sp)->_line[y].text,
- Width * sizeof(chtype));
+ if (SP_PARM->_endwin) {
+
+ T(("coming back from shell mode"));
+ NCURSES_SP_NAME(reset_prog_mode) (NCURSES_SP_ARG);
+
+ NCURSES_SP_NAME(_nc_mvcur_resume) (NCURSES_SP_ARG);
+ NCURSES_SP_NAME(_nc_screen_resume) (NCURSES_SP_ARG);
+ SP_PARM->_mouse_resume(SP_PARM);
+
+ SP_PARM->_endwin = FALSE;
}
- CurScreen(sp)->_clear = FALSE;
- NewScreen(sp)->_clear = FALSE;
- touchwin(NewScreen(sp));
- }
- for (y = 0; y < nonempty; y++) {
- x0 = NewScreen(sp)->_line[y].firstchar;
- if (x0 != _NOCHANGE) {
- x1 = NewScreen(sp)->_line[y].lastchar;
- n = x1 - x0 + 1;
- if (n > 0) {
- memcpy(CurScreen(sp)->_line[y].text + x0,
- NewScreen(sp)->_line[y].text + x0,
- n * sizeof(chtype));
- con_write(TCB,
- y,
- x0,
- ((chtype *) CurScreen(sp)->_line[y].text) + x0, n);
+ if ((CurScreen(sp)->_clear || NewScreen(sp)->_clear)) {
+ int x;
+#if USE_WIDEC_SUPPORT
+ cchar_t empty[Width];
+ wchar_t blank[2] =
+ {
+ L' ', L'\0'
+ };
+
+ for (x = 0; x < Width; x++)
+ setcchar(&empty[x], blank, 0, 0, 0);
+#else
+ chtype empty[Width];
+
+ for (x = 0; x < Width; x++)
+ empty[x] = ' ';
+#endif
+
+ for (y = 0; y < nonempty; y++) {
+ con_write(TCB, y, 0, empty, Width);
+ memcpy(empty,
+ CurScreen(sp)->_line[y].text,
+ (size_t) Width * sizeof(empty[0]));
+ }
+ CurScreen(sp)->_clear = FALSE;
+ NewScreen(sp)->_clear = FALSE;
+ touchwin(NewScreen(sp));
+ T(("... cleared %dx%d lines @%d of screen", nonempty, Width,
+ AdjustY()));
+ }
+
+ for (y = 0; y < nonempty; y++) {
+ x0 = NewScreen(sp)->_line[y].firstchar;
+ if (x0 != _NOCHANGE) {
+#if EXP_OPTIMIZE
+ int x2;
+ int limit = NewScreen(sp)->_line[y].lastchar;
+ while ((x1 = EndChange(x0)) <= limit) {
+ while ((x2 = NextChange(x1)) <= limit && x2 <= (x1 + 2)) {
+ x1 = x2;
+ }
+ n = x1 - x0 + 1;
+ memcpy(&CurScreen(sp)->_line[y].text[x0],
+ &NewScreen(sp)->_line[y].text[x0],
+ n * sizeof(CurScreen(sp)->_line[y].text[x0]));
+ con_write(TCB,
+ y,
+ x0,
+ &CurScreen(sp)->_line[y].text[x0], n);
+ x0 = NextChange(x1);
+ }
/* mark line changed successfully */
if (y <= NewScreen(sp)->_maxy) {
@@ -234,95 +566,160 @@ drv_doupdate(TERMINAL_CONTROL_BLOCK * TCB)
if (y <= CurScreen(sp)->_maxy) {
MARK_NOCHANGE(CurScreen(sp), y);
}
+#else
+ x1 = NewScreen(sp)->_line[y].lastchar;
+ n = x1 - x0 + 1;
+ if (n > 0) {
+ memcpy(&CurScreen(sp)->_line[y].text[x0],
+ &NewScreen(sp)->_line[y].text[x0],
+ (size_t) n * sizeof(CurScreen(sp)->_line[y].text[x0]));
+ con_write(TCB,
+ y,
+ x0,
+ &CurScreen(sp)->_line[y].text[x0], n);
+
+ /* mark line changed successfully */
+ if (y <= NewScreen(sp)->_maxy) {
+ MARK_NOCHANGE(NewScreen(sp), y);
+ }
+ if (y <= CurScreen(sp)->_maxy) {
+ MARK_NOCHANGE(CurScreen(sp), y);
+ }
+ }
+#endif
}
}
- }
- /* put everything back in sync */
- for (y = nonempty; y <= NewScreen(sp)->_maxy; y++) {
- MARK_NOCHANGE(NewScreen(sp), y);
- }
- for (y = nonempty; y <= CurScreen(sp)->_maxy; y++) {
- MARK_NOCHANGE(CurScreen(sp), y);
- }
+ /* put everything back in sync */
+ for (y = nonempty; y <= NewScreen(sp)->_maxy; y++) {
+ MARK_NOCHANGE(NewScreen(sp), y);
+ }
+ for (y = nonempty; y <= CurScreen(sp)->_maxy; y++) {
+ MARK_NOCHANGE(CurScreen(sp), y);
+ }
- if (!NewScreen(sp)->_leaveok) {
- CurScreen(sp)->_curx = NewScreen(sp)->_curx;
- CurScreen(sp)->_cury = NewScreen(sp)->_cury;
+ if (!NewScreen(sp)->_leaveok) {
+ CurScreen(sp)->_curx = NewScreen(sp)->_curx;
+ CurScreen(sp)->_cury = NewScreen(sp)->_cury;
- TCB->drv->hwcur(TCB, 0, 0, CurScreen(sp)->_cury, CurScreen(sp)->_curx);
+ TCB->drv->td_hwcur(TCB,
+ 0, 0,
+ CurScreen(sp)->_cury, CurScreen(sp)->_curx);
+ }
+ selectActiveHandle();
+ result = OK;
}
- SetConsoleActiveScreenBuffer(TCB->hdl);
- return OK;
+ returnCode(result);
}
static bool
-drv_CanHandle(TERMINAL_CONTROL_BLOCK * TCB,
- const char *tname,
- int *errret GCC_UNUSED)
+wcon_CanHandle(TERMINAL_CONTROL_BLOCK * TCB,
+ const char *tname,
+ int *errret GCC_UNUSED)
{
bool code = FALSE;
- T((T_CALLED("win32con::drv_CanHandle(%p)"), TCB));
+ T((T_CALLED("win32con::wcon_CanHandle(%p)"), TCB));
- assert(TCB != 0);
- assert(tname != 0);
+ assert((TCB != 0) && (tname != 0));
TCB->magic = WINMAGIC;
- if (*tname == 0 || *tname == 0) {
- code = TRUE;
- } else {
- TERMINAL my_term;
- int status;
- code = FALSE;
-#if (USE_DATABASE || USE_TERMCAP)
- status = _nc_setup_tinfo(tname, &my_term.type);
-#else
- status = TGETENT_NO;
-#endif
- if (status != TGETENT_YES) {
- const TERMTYPE *fallback = _nc_fallback(tname);
-
- if (fallback) {
- my_term.type = *fallback;
- status = TGETENT_YES;
- } else if (!strcmp(tname, "unknown")) {
- code = TRUE;
- }
- }
- if (status == TGETENT_YES) {
- if (generic_type || hard_copy)
- code = TRUE;
+ if (tname == 0 || *tname == 0)
+ code = TRUE;
+ else if (tname != 0 && *tname == '#') {
+ /*
+ * Use "#" (a character which cannot begin a terminal's name) to
+ * select specific driver from the table.
+ *
+ * In principle, we could have more than one non-terminfo driver,
+ * e.g., "win32gui".
+ */
+ size_t n = strlen(tname + 1);
+ if (n != 0
+ && ((strncmp(tname + 1, "win32console", n) == 0)
+ || (strncmp(tname + 1, "win32con", n) == 0))) {
+ code = TRUE;
}
+ } else if (tname != 0 && stricmp(tname, "unknown") == 0) {
+ code = TRUE;
}
- if (code) {
- if ((TCB->term.type.Booleans) == 0) {
- _nc_init_entry(&(TCB->term.type));
- }
+ /*
+ * This is intentional, to avoid unnecessary breakage of applications
+ * using <term.h> symbols.
+ */
+ if (code && (TCB->term.type.Booleans == 0)) {
+ _nc_init_termtype(&(TCB->term.type));
}
+ if (!code) {
+ if (_nc_mingw_isconsole(0))
+ CON.isTermInfoConsole = TRUE;
+ }
returnBool(code);
}
static int
-drv_dobeepflash(TERMINAL_CONTROL_BLOCK * TCB,
- bool beepFlag GCC_UNUSED)
+wcon_dobeepflash(TERMINAL_CONTROL_BLOCK * TCB,
+ int beepFlag)
{
SCREEN *sp;
- int res = ERR;
+ int res = OK;
+
+ int high = (CON.SBI.srWindow.Bottom - CON.SBI.srWindow.Top + 1);
+ int wide = (CON.SBI.srWindow.Right - CON.SBI.srWindow.Left + 1);
+ int max_cells = (high * wide);
+ int i;
+
+ CHAR_INFO this_screen[max_cells];
+ CHAR_INFO that_screen[max_cells];
+ COORD this_size;
+ SMALL_RECT this_region;
+ COORD bufferCoord;
AssertTCB();
+
SetSP();
+ this_region.Top = CON.SBI.srWindow.Top;
+ this_region.Left = CON.SBI.srWindow.Left;
+ this_region.Bottom = CON.SBI.srWindow.Bottom;
+ this_region.Right = CON.SBI.srWindow.Right;
+
+ this_size.X = (SHORT) wide;
+ this_size.Y = (SHORT) high;
+
+ bufferCoord.X = this_region.Left;
+ bufferCoord.Y = this_region.Top;
+
+ if (!beepFlag &&
+ read_screen(CON.hdl,
+ this_screen,
+ this_size,
+ bufferCoord,
+ &this_region)) {
+
+ memcpy(that_screen, this_screen, sizeof(that_screen));
+
+ for (i = 0; i < max_cells; i++) {
+ that_screen[i].Attributes = RevAttr(that_screen[i].Attributes);
+ }
+
+ write_screen(CON.hdl, that_screen, this_size, bufferCoord, &this_region);
+ Sleep(200);
+ write_screen(CON.hdl, this_screen, this_size, bufferCoord, &this_region);
+
+ } else {
+ MessageBeep(MB_ICONWARNING); /* MB_OK might be better */
+ }
return res;
}
static int
-drv_print(TERMINAL_CONTROL_BLOCK * TCB,
- char *data GCC_UNUSED,
- int len GCC_UNUSED)
+wcon_print(TERMINAL_CONTROL_BLOCK * TCB,
+ char *data GCC_UNUSED,
+ int len GCC_UNUSED)
{
SCREEN *sp;
@@ -333,9 +730,9 @@ drv_print(TERMINAL_CONTROL_BLOCK * TCB,
}
static int
-drv_defaultcolors(TERMINAL_CONTROL_BLOCK * TCB,
- int fg GCC_UNUSED,
- int bg GCC_UNUSED)
+wcon_defaultcolors(TERMINAL_CONTROL_BLOCK * TCB,
+ int fg GCC_UNUSED,
+ int bg GCC_UNUSED)
{
SCREEN *sp;
int code = ERR;
@@ -346,39 +743,73 @@ drv_defaultcolors(TERMINAL_CONTROL_BLOCK * TCB,
return (code);
}
+static bool
+get_SBI(void)
+{
+ bool rc = FALSE;
+ if (GetConsoleScreenBufferInfo(CON.hdl, &(CON.SBI))) {
+ T(("GetConsoleScreenBufferInfo"));
+ T(("... buffer(X:%d Y:%d)",
+ CON.SBI.dwSize.X,
+ CON.SBI.dwSize.Y));
+ T(("... window(X:%d Y:%d)",
+ CON.SBI.dwMaximumWindowSize.X,
+ CON.SBI.dwMaximumWindowSize.Y));
+ T(("... cursor(X:%d Y:%d)",
+ CON.SBI.dwCursorPosition.X,
+ CON.SBI.dwCursorPosition.Y));
+ T(("... display(Top:%d Bottom:%d Left:%d Right:%d)",
+ CON.SBI.srWindow.Top,
+ CON.SBI.srWindow.Bottom,
+ CON.SBI.srWindow.Left,
+ CON.SBI.srWindow.Right));
+ if (CON.buffered) {
+ CON.origin.X = 0;
+ CON.origin.Y = 0;
+ } else {
+ CON.origin.X = CON.SBI.srWindow.Left;
+ CON.origin.Y = CON.SBI.srWindow.Top;
+ }
+ rc = TRUE;
+ } else {
+ T(("GetConsoleScreenBufferInfo ERR"));
+ }
+ return rc;
+}
+
static void
-drv_setcolor(TERMINAL_CONTROL_BLOCK * TCB,
- bool fore,
- int color,
- int (*outc) (SCREEN *, int) GCC_UNUSED)
+wcon_setcolor(TERMINAL_CONTROL_BLOCK * TCB,
+ int fore,
+ int color,
+ int (*outc) (SCREEN *, int) GCC_UNUSED)
{
AssertTCB();
- if (TCB && !InvalidConsoleHandle(TCB->hdl)) {
+ if (okConsoleHandle(TCB)) {
WORD a = MapColor(fore, color);
- a = ((PropOf(TCB)->SBI.wAttributes) & (fore ? 0xfff8 : 0xff8f)) | a;
- SetConsoleTextAttribute(TCB->hdl, a);
- GetConsoleScreenBufferInfo(TCB->hdl, &(PropOf(TCB)->SBI));
+ a |= (WORD) ((CON.SBI.wAttributes) & (fore ? 0xfff8 : 0xff8f));
+ SetConsoleTextAttribute(CON.hdl, a);
+ get_SBI();
}
}
static bool
-drv_rescol(TERMINAL_CONTROL_BLOCK * TCB)
+wcon_rescol(TERMINAL_CONTROL_BLOCK * TCB)
{
bool res = FALSE;
AssertTCB();
- if (TCB && !InvalidConsoleHandle(TCB->hdl)) {
+ if (okConsoleHandle(TCB)) {
WORD a = FOREGROUND_BLUE | FOREGROUND_RED | FOREGROUND_GREEN;
- SetConsoleTextAttribute(TCB->hdl, a);
- GetConsoleScreenBufferInfo(TCB->hdl, &(PropOf(TCB)->SBI));
+ SetConsoleTextAttribute(CON.hdl, a);
+ get_SBI();
res = TRUE;
}
return res;
}
static bool
-drv_rescolors(TERMINAL_CONTROL_BLOCK * TCB)
+wcon_rescolors(TERMINAL_CONTROL_BLOCK * TCB)
{
int result = FALSE;
SCREEN *sp;
@@ -390,29 +821,42 @@ drv_rescolors(TERMINAL_CONTROL_BLOCK * TCB)
}
static int
-drv_size(TERMINAL_CONTROL_BLOCK * TCB, int *Lines, int *Cols)
+wcon_size(TERMINAL_CONTROL_BLOCK * TCB, int *Lines, int *Cols)
{
+ int result = ERR;
+
AssertTCB();
- if (TCB == NULL || Lines == NULL || Cols == NULL || InvalidConsoleHandle(TCB->hdl))
- return ERR;
+ T((T_CALLED("win32con::wcon_size(%p)"), TCB));
- *Lines = (int) (PropOf(TCB)->SBI.dwSize.Y);
- *Cols = (int) (PropOf(TCB)->SBI.dwSize.X);
- return OK;
+ if (okConsoleHandle(TCB) &&
+ Lines != NULL &&
+ Cols != NULL) {
+ if (CON.buffered) {
+ *Lines = (int) (CON.SBI.dwSize.Y);
+ *Cols = (int) (CON.SBI.dwSize.X);
+ } else {
+ *Lines = (int) (CON.SBI.srWindow.Bottom + 1 -
+ CON.SBI.srWindow.Top);
+ *Cols = (int) (CON.SBI.srWindow.Right + 1 -
+ CON.SBI.srWindow.Left);
+ }
+ result = OK;
+ }
+ returnCode(result);
}
static int
-drv_setsize(TERMINAL_CONTROL_BLOCK * TCB GCC_UNUSED,
- int l GCC_UNUSED,
- int c GCC_UNUSED)
+wcon_setsize(TERMINAL_CONTROL_BLOCK * TCB GCC_UNUSED,
+ int l GCC_UNUSED,
+ int c GCC_UNUSED)
{
AssertTCB();
return ERR;
}
static int
-drv_sgmode(TERMINAL_CONTROL_BLOCK * TCB, bool setFlag, TTY * buf)
+wcon_sgmode(TERMINAL_CONTROL_BLOCK * TCB, int setFlag, TTY * buf)
{
DWORD dwFlag = 0;
tcflag_t iflag;
@@ -427,48 +871,48 @@ drv_sgmode(TERMINAL_CONTROL_BLOCK * TCB, bool setFlag, TTY * buf)
iflag = buf->c_iflag;
lflag = buf->c_lflag;
- GetConsoleMode(TCB->inp, &dwFlag);
+ GetConsoleMode(CON.inp, &dwFlag);
if (lflag & ICANON)
dwFlag |= ENABLE_LINE_INPUT;
else
- dwFlag &= ~ENABLE_LINE_INPUT;
+ dwFlag &= (DWORD) (~ENABLE_LINE_INPUT);
if (lflag & ECHO)
dwFlag |= ENABLE_ECHO_INPUT;
else
- dwFlag &= ~ENABLE_ECHO_INPUT;
+ dwFlag &= (DWORD) (~ENABLE_ECHO_INPUT);
if (iflag & BRKINT)
dwFlag |= ENABLE_PROCESSED_INPUT;
else
- dwFlag &= ~ENABLE_PROCESSED_INPUT;
+ dwFlag &= (DWORD) (~ENABLE_PROCESSED_INPUT);
dwFlag |= ENABLE_MOUSE_INPUT;
buf->c_iflag = iflag;
buf->c_lflag = lflag;
- SetConsoleMode(TCB->inp, dwFlag);
+ SetConsoleMode(CON.inp, dwFlag);
TCB->term.Nttyb = *buf;
} else {
iflag = TCB->term.Nttyb.c_iflag;
lflag = TCB->term.Nttyb.c_lflag;
- GetConsoleMode(TCB->inp, &dwFlag);
+ GetConsoleMode(CON.inp, &dwFlag);
if (dwFlag & ENABLE_LINE_INPUT)
lflag |= ICANON;
else
- lflag &= ~ICANON;
+ lflag &= (tcflag_t) (~ICANON);
if (dwFlag & ENABLE_ECHO_INPUT)
lflag |= ECHO;
else
- lflag &= ~ECHO;
+ lflag &= (tcflag_t) (~ECHO);
if (dwFlag & ENABLE_PROCESSED_INPUT)
iflag |= BRKINT;
else
- iflag &= ~BRKINT;
+ iflag &= (tcflag_t) (~BRKINT);
TCB->term.Nttyb.c_iflag = iflag;
TCB->term.Nttyb.c_lflag = lflag;
@@ -478,8 +922,86 @@ drv_sgmode(TERMINAL_CONTROL_BLOCK * TCB, bool setFlag, TTY * buf)
return OK;
}
+#define MIN_WIDE 80
+#define MIN_HIGH 24
+
+/*
+ * In "normal" mode, reset the buffer- and window-sizes back to their original values.
+ */
+static void
+set_scrollback(bool normal, CONSOLE_SCREEN_BUFFER_INFO * info)
+{
+ SMALL_RECT rect;
+ COORD coord;
+ bool changed = FALSE;
+
+ T((T_CALLED("win32con::set_scrollback(%s)"),
+ (normal
+ ? "normal"
+ : "application")));
+
+ T(("... SBI.srWindow %d,%d .. %d,%d",
+ info->srWindow.Top,
+ info->srWindow.Left,
+ info->srWindow.Bottom,
+ info->srWindow.Right));
+ T(("... SBI.dwSize %dx%d",
+ info->dwSize.Y,
+ info->dwSize.X));
+
+ if (normal) {
+ rect = info->srWindow;
+ coord = info->dwSize;
+ if (memcmp(info, &CON.SBI, sizeof(*info)) != 0) {
+ changed = TRUE;
+ CON.SBI = *info;
+ }
+ } else {
+ int high = info->srWindow.Bottom - info->srWindow.Top + 1;
+ int wide = info->srWindow.Right - info->srWindow.Left + 1;
+
+ if (high < MIN_HIGH) {
+ T(("... height %d < %d", high, MIN_HIGH));
+ high = MIN_HIGH;
+ changed = TRUE;
+ }
+ if (wide < MIN_WIDE) {
+ T(("... width %d < %d", wide, MIN_WIDE));
+ wide = MIN_WIDE;
+ changed = TRUE;
+ }
+
+ rect.Left =
+ rect.Top = 0;
+ rect.Right = (SHORT) (wide - 1);
+ rect.Bottom = (SHORT) (high - 1);
+
+ coord.X = (SHORT) wide;
+ coord.Y = (SHORT) high;
+
+ if (info->dwSize.Y != high ||
+ info->dwSize.X != wide ||
+ info->srWindow.Top != 0 ||
+ info->srWindow.Left != 0) {
+ changed = TRUE;
+ }
+
+ }
+
+ if (changed) {
+ T(("... coord %d,%d", coord.Y, coord.X));
+ T(("... rect %d,%d - %d,%d",
+ rect.Top, rect.Left,
+ rect.Bottom, rect.Right));
+ SetConsoleScreenBufferSize(CON.hdl, coord); /* dwSize */
+ SetConsoleWindowInfo(CON.hdl, TRUE, &rect); /* srWindow */
+ get_SBI();
+ }
+ returnVoid;
+}
+
static int
-drv_mode(TERMINAL_CONTROL_BLOCK * TCB, bool progFlag, bool defFlag)
+wcon_mode(TERMINAL_CONTROL_BLOCK * TCB, int progFlag, int defFlag)
{
SCREEN *sp;
TERMINAL *_term = (TERMINAL *) TCB;
@@ -488,30 +1010,35 @@ drv_mode(TERMINAL_CONTROL_BLOCK * TCB, bool progFlag, bool defFlag)
AssertTCB();
sp = TCB->csp;
- PropOf(TCB)->progMode = progFlag;
- SetConsoleActiveScreenBuffer(progFlag ? TCB->hdl : TCB->out);
+ T((T_CALLED("win32con::wcon_mode(%p, prog=%d, def=%d)"), TCB, progFlag, defFlag));
+ CON.progMode = progFlag;
+ CON.lastOut = progFlag ? CON.hdl : CON.out;
+ SetConsoleActiveScreenBuffer(CON.lastOut);
if (progFlag) /* prog mode */ {
if (defFlag) {
- if ((drv_sgmode(TCB, FALSE, &(_term->Nttyb)) == OK)) {
- _term->Nttyb.c_oflag &= ~OFLAGS_TABS;
+ if ((wcon_sgmode(TCB, FALSE, &(_term->Nttyb)) == OK)) {
+ _term->Nttyb.c_oflag &= (tcflag_t) (~OFLAGS_TABS);
code = OK;
}
} else {
/* reset_prog_mode */
- if (drv_sgmode(TCB, TRUE, &(_term->Nttyb)) == OK) {
+ if (wcon_sgmode(TCB, TRUE, &(_term->Nttyb)) == OK) {
if (sp) {
if (sp->_keypad_on)
_nc_keypad(sp, TRUE);
- NC_BUFFERED(sp, TRUE);
+ }
+ if (!CON.buffered) {
+ set_scrollback(FALSE, &CON.SBI);
}
code = OK;
}
}
+ T(("... buffered:%d, clear:%d", CON.buffered, CurScreen(sp)->_clear));
} else { /* shell mode */
if (defFlag) {
/* def_shell_mode */
- if (drv_sgmode(TCB, FALSE, &(_term->Ottyb)) == OK) {
+ if (wcon_sgmode(TCB, FALSE, &(_term->Ottyb)) == OK) {
code = OK;
}
} else {
@@ -519,22 +1046,27 @@ drv_mode(TERMINAL_CONTROL_BLOCK * TCB, bool progFlag, bool defFlag)
if (sp) {
_nc_keypad(sp, FALSE);
NCURSES_SP_NAME(_nc_flush) (sp);
- NC_BUFFERED(sp, FALSE);
}
- code = drv_sgmode(TCB, TRUE, &(_term->Ottyb));
+ code = wcon_sgmode(TCB, TRUE, &(_term->Ottyb));
+ if (!CON.buffered) {
+ set_scrollback(TRUE, &CON.save_SBI);
+ if (!restore_original_screen())
+ code = ERR;
+ }
+ SetConsoleCursorInfo(CON.hdl, &CON.save_CI);
}
}
- return (code);
+ returnCode(code);
}
static void
-drv_screen_init(SCREEN *sp GCC_UNUSED)
+wcon_screen_init(SCREEN *sp GCC_UNUSED)
{
}
static void
-drv_wrap(SCREEN *sp GCC_UNUSED)
+wcon_wrap(SCREEN *sp GCC_UNUSED)
{
}
@@ -557,17 +1089,38 @@ keycompare(const void *el1, const void *el2)
}
static int
-MapKey(TERMINAL_CONTROL_BLOCK * TCB, WORD vKey)
+MapKey(WORD vKey)
{
WORD nKey = 0;
void *res;
LONG key = GenMap(vKey, 0);
int code = -1;
- AssertTCB();
+ res = bsearch(&key,
+ CON.map,
+ (size_t) (N_INI + FKEYS),
+ sizeof(keylist[0]),
+ keycompare);
+ if (res) {
+ key = *((LONG *) res);
+ nKey = LOWORD(key);
+ code = (int) (nKey & 0x7fff);
+ if (nKey & 0x8000)
+ code = -code;
+ }
+ return code;
+}
+
+static int
+AnsiKey(WORD vKey)
+{
+ WORD nKey = 0;
+ void *res;
+ LONG key = GenMap(vKey, 0);
+ int code = -1;
res = bsearch(&key,
- PropOf(TCB)->map,
+ CON.ansi_map,
(size_t) (N_INI + FKEYS),
sizeof(keylist[0]),
keycompare);
@@ -582,9 +1135,9 @@ MapKey(TERMINAL_CONTROL_BLOCK * TCB, WORD vKey)
}
static void
-drv_release(TERMINAL_CONTROL_BLOCK * TCB)
+wcon_release(TERMINAL_CONTROL_BLOCK * TCB)
{
- T((T_CALLED("win32con::drv_release(%p)"), TCB));
+ T((T_CALLED("win32con::wcon_release(%p)"), TCB));
AssertTCB();
if (TCB->prop)
@@ -593,38 +1146,96 @@ drv_release(TERMINAL_CONTROL_BLOCK * TCB)
returnVoid;
}
-static void
-drv_init(TERMINAL_CONTROL_BLOCK * TCB)
+static bool
+read_screen_data(void)
{
- DWORD num_buttons;
+ bool result = FALSE;
+ COORD bufferCoord;
+ size_t want;
+
+ CON.save_size.X = (SHORT) (CON.save_region.Right
+ - CON.save_region.Left + 1);
+ CON.save_size.Y = (SHORT) (CON.save_region.Bottom
+ - CON.save_region.Top + 1);
+
+ want = (size_t) (CON.save_size.X * CON.save_size.Y);
+
+ if ((CON.save_screen = malloc(want * sizeof(CHAR_INFO))) != 0) {
+ bufferCoord.X = (SHORT) (CON.window_only ? CON.SBI.srWindow.Left : 0);
+ bufferCoord.Y = (SHORT) (CON.window_only ? CON.SBI.srWindow.Top : 0);
+
+ T(("... reading console %s %dx%d into %d,%d - %d,%d at %d,%d",
+ CON.window_only ? "window" : "buffer",
+ CON.save_size.Y, CON.save_size.X,
+ CON.save_region.Top,
+ CON.save_region.Left,
+ CON.save_region.Bottom,
+ CON.save_region.Right,
+ bufferCoord.Y,
+ bufferCoord.X));
+
+ if (read_screen(CON.hdl,
+ CON.save_screen,
+ CON.save_size,
+ bufferCoord,
+ &CON.save_region)) {
+ result = TRUE;
+ } else {
+ T((" error %#lx", (unsigned long) GetLastError()));
+ FreeAndNull(CON.save_screen);
+ }
+ }
- T((T_CALLED("win32con::drv_init(%p)"), TCB));
+ return result;
+}
- AssertTCB();
+/*
+ * Attempt to save the screen contents. PDCurses does this if
+ * PDC_RESTORE_SCREEN is set, giving the same visual appearance on
+ * restoration as if the library had allocated a console buffer. MSDN
+ * says that the data which can be read is limited to 64Kb (and may be
+ * less).
+ */
+static bool
+save_original_screen(void)
+{
+ bool result = FALSE;
- if (TCB) {
- BOOL b = AllocConsole();
- WORD a;
- int i;
+ CON.save_region.Top = 0;
+ CON.save_region.Left = 0;
+ CON.save_region.Bottom = (SHORT) (CON.SBI.dwSize.Y - 1);
+ CON.save_region.Right = (SHORT) (CON.SBI.dwSize.X - 1);
- if (!b)
- b = AttachConsole(ATTACH_PARENT_PROCESS);
+ if (read_screen_data()) {
+ result = TRUE;
+ } else {
- TCB->inp = GetStdHandle(STD_INPUT_HANDLE);
- TCB->out = GetStdHandle(STD_OUTPUT_HANDLE);
+ CON.save_region.Top = CON.SBI.srWindow.Top;
+ CON.save_region.Left = CON.SBI.srWindow.Left;
+ CON.save_region.Bottom = CON.SBI.srWindow.Bottom;
+ CON.save_region.Right = CON.SBI.srWindow.Right;
- if (getenv("NCGDB"))
- TCB->hdl = TCB->out;
- else
- TCB->hdl = CreateConsoleScreenBuffer(GENERIC_READ | GENERIC_WRITE,
- 0,
- NULL,
- CONSOLE_TEXTMODE_BUFFER,
- NULL);
-
- if (!InvalidConsoleHandle(TCB->hdl)) {
- TCB->prop = typeCalloc(Properties, 1);
- GetConsoleScreenBufferInfo(TCB->hdl, &(PropOf(TCB)->SBI));
+ CON.window_only = TRUE;
+
+ if (read_screen_data()) {
+ result = TRUE;
+ }
+ }
+
+ T(("... save original screen contents %s", result ? "ok" : "err"));
+ return result;
+}
+
+static void
+wcon_init(TERMINAL_CONTROL_BLOCK * TCB)
+{
+ T((T_CALLED("win32con::wcon_init(%p)"), TCB));
+
+ AssertTCB();
+
+ if (TCB) {
+ if (CON.hdl == INVALID_HANDLE_VALUE) {
+ returnVoid;
}
TCB->info.initcolor = TRUE;
@@ -640,43 +1251,18 @@ drv_init(TERMINAL_CONTROL_BLOCK * TCB)
TCB->info.nocolorvideo = 1;
TCB->info.tabsize = 8;
- if (GetNumberOfConsoleMouseButtons(&num_buttons)) {
- T(("mouse has %ld buttons", num_buttons));
- TCB->info.numbuttons = num_buttons;
- } else {
- TCB->info.numbuttons = 1;
- }
-
+ TCB->info.numbuttons = CON.numButtons;
TCB->info.defaultPalette = _nc_cga_palette;
- for (i = 0; i < (N_INI + FKEYS); i++) {
- if (i < N_INI)
- PropOf(TCB)->rmap[i] = PropOf(TCB)->map[i] = keylist[i];
- else
- PropOf(TCB)->rmap[i] = PropOf(TCB)->map[i] =
- GenMap((VK_F1 + (i - N_INI)), (KEY_F(1) + (i - N_INI)));
- }
- qsort(PropOf(TCB)->map,
- (size_t) (MAPSIZE),
- sizeof(keylist[0]),
- keycompare);
- qsort(PropOf(TCB)->rmap,
- (size_t) (MAPSIZE),
- sizeof(keylist[0]),
- rkeycompare);
-
- a = MapColor(true, COLOR_WHITE) | MapColor(false, COLOR_BLACK);
- for (i = 0; i < NUMPAIRS; i++)
- PropOf(TCB)->pairs[i] = a;
}
returnVoid;
}
static void
-drv_initpair(TERMINAL_CONTROL_BLOCK * TCB,
- short pair,
- short f,
- short b)
+wcon_initpair(TERMINAL_CONTROL_BLOCK * TCB,
+ int pair,
+ int f,
+ int b)
{
SCREEN *sp;
@@ -685,16 +1271,16 @@ drv_initpair(TERMINAL_CONTROL_BLOCK * TCB,
if ((pair > 0) && (pair < NUMPAIRS) && (f >= 0) && (f < 8)
&& (b >= 0) && (b < 8)) {
- PropOf(TCB)->pairs[pair] = MapColor(true, f) | MapColor(false, b);
+ CON.pairs[pair] = MapColor(true, f) | MapColor(false, b);
}
}
static void
-drv_initcolor(TERMINAL_CONTROL_BLOCK * TCB,
- short color GCC_UNUSED,
- short r GCC_UNUSED,
- short g GCC_UNUSED,
- short b GCC_UNUSED)
+wcon_initcolor(TERMINAL_CONTROL_BLOCK * TCB,
+ int color GCC_UNUSED,
+ int r GCC_UNUSED,
+ int g GCC_UNUSED,
+ int b GCC_UNUSED)
{
SCREEN *sp;
@@ -703,11 +1289,11 @@ drv_initcolor(TERMINAL_CONTROL_BLOCK * TCB,
}
static void
-drv_do_color(TERMINAL_CONTROL_BLOCK * TCB,
- short old_pair GCC_UNUSED,
- short pair GCC_UNUSED,
- bool reverse GCC_UNUSED,
- int (*outc) (SCREEN *, int) GCC_UNUSED
+wcon_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
)
{
SCREEN *sp;
@@ -717,7 +1303,7 @@ drv_do_color(TERMINAL_CONTROL_BLOCK * TCB,
}
static void
-drv_initmouse(TERMINAL_CONTROL_BLOCK * TCB)
+wcon_initmouse(TERMINAL_CONTROL_BLOCK * TCB)
{
SCREEN *sp;
@@ -728,7 +1314,7 @@ drv_initmouse(TERMINAL_CONTROL_BLOCK * TCB)
}
static int
-drv_testmouse(TERMINAL_CONTROL_BLOCK * TCB, int delay)
+wcon_testmouse(TERMINAL_CONTROL_BLOCK * TCB, int delay)
{
int rc = 0;
SCREEN *sp;
@@ -739,36 +1325,36 @@ drv_testmouse(TERMINAL_CONTROL_BLOCK * TCB, int delay)
if (sp->_drv_mouse_head < sp->_drv_mouse_tail) {
rc = TW_MOUSE;
} else {
- rc = TCBOf(sp)->drv->twait(TCBOf(sp),
- TWAIT_MASK,
- delay,
- (int *) 0
- EVENTLIST_2nd(evl));
+ rc = TCBOf(sp)->drv->td_twait(TCBOf(sp),
+ TWAIT_MASK,
+ delay,
+ (int *) 0
+ EVENTLIST_2nd(evl));
}
return rc;
}
static int
-drv_mvcur(TERMINAL_CONTROL_BLOCK * TCB,
- int yold GCC_UNUSED, int xold GCC_UNUSED,
- int y, int x)
+wcon_mvcur(TERMINAL_CONTROL_BLOCK * TCB,
+ int yold GCC_UNUSED, int xold GCC_UNUSED,
+ int y, int x)
{
int ret = ERR;
- if (TCB && !InvalidConsoleHandle(TCB->hdl)) {
+ if (okConsoleHandle(TCB)) {
COORD loc;
loc.X = (short) x;
- loc.Y = (short) y;
- SetConsoleCursorPosition(TCB->hdl, loc);
+ loc.Y = (short) (y + AdjustY());
+ SetConsoleCursorPosition(CON.hdl, loc);
ret = OK;
}
return ret;
}
static void
-drv_hwlabel(TERMINAL_CONTROL_BLOCK * TCB,
- int labnum GCC_UNUSED,
- char *text GCC_UNUSED)
+wcon_hwlabel(TERMINAL_CONTROL_BLOCK * TCB,
+ int labnum GCC_UNUSED,
+ char *text GCC_UNUSED)
{
SCREEN *sp;
@@ -777,8 +1363,8 @@ drv_hwlabel(TERMINAL_CONTROL_BLOCK * TCB,
}
static void
-drv_hwlabelOnOff(TERMINAL_CONTROL_BLOCK * TCB,
- bool OnFlag GCC_UNUSED)
+wcon_hwlabelOnOff(TERMINAL_CONTROL_BLOCK * TCB,
+ int OnFlag GCC_UNUSED)
{
SCREEN *sp;
@@ -787,7 +1373,7 @@ drv_hwlabelOnOff(TERMINAL_CONTROL_BLOCK * TCB,
}
static chtype
-drv_conattr(TERMINAL_CONTROL_BLOCK * TCB GCC_UNUSED)
+wcon_conattr(TERMINAL_CONTROL_BLOCK * TCB GCC_UNUSED)
{
chtype res = A_NORMAL;
res |= (A_BOLD | A_DIM | A_REVERSE | A_STANDOUT | A_COLOR);
@@ -795,7 +1381,7 @@ drv_conattr(TERMINAL_CONTROL_BLOCK * TCB GCC_UNUSED)
}
static void
-drv_setfilter(TERMINAL_CONTROL_BLOCK * TCB)
+wcon_setfilter(TERMINAL_CONTROL_BLOCK * TCB)
{
SCREEN *sp;
@@ -804,9 +1390,9 @@ drv_setfilter(TERMINAL_CONTROL_BLOCK * TCB)
}
static void
-drv_initacs(TERMINAL_CONTROL_BLOCK * TCB,
- chtype *real_map GCC_UNUSED,
- chtype *fake_map GCC_UNUSED)
+wcon_initacs(TERMINAL_CONTROL_BLOCK * TCB,
+ chtype *real_map GCC_UNUSED,
+ chtype *fake_map GCC_UNUSED)
{
#define DATA(a,b) { a, b }
static struct {
@@ -844,7 +1430,7 @@ drv_initacs(TERMINAL_CONTROL_BLOCK * TCB,
SetSP();
for (n = 0; n < SIZEOF(table); ++n) {
- real_map[table[n].acs_code] = table[n].use_code | A_ALTCHARSET;
+ real_map[table[n].acs_code] = (chtype) table[n].use_code | A_ALTCHARSET;
if (sp != 0)
sp->_screen_acs_map[table[n].acs_code] = TRUE;
}
@@ -869,11 +1455,11 @@ tdiff(FILETIME fstart, FILETIME fend)
static int
Adjust(int milliseconds, int diff)
{
- if (milliseconds == INFINITY)
- return milliseconds;
- milliseconds -= diff;
- if (milliseconds < 0)
- milliseconds = 0;
+ if (milliseconds != INFINITY) {
+ milliseconds -= diff;
+ if (milliseconds < 0)
+ milliseconds = 0;
+ }
return milliseconds;
}
@@ -884,13 +1470,12 @@ Adjust(int milliseconds, int diff)
RIGHTMOST_BUTTON_PRESSED)
static int
-decode_mouse(TERMINAL_CONTROL_BLOCK * TCB, int mask)
+decode_mouse(SCREEN *sp, int mask)
{
- SCREEN *sp;
int result = 0;
- AssertTCB();
- SetSP();
+ (void) sp;
+ assert(sp && console_initialized);
if (mask & FROM_LEFT_1ST_BUTTON_PRESSED)
result |= BUTTON1_PRESSED;
@@ -902,7 +1487,7 @@ decode_mouse(TERMINAL_CONTROL_BLOCK * TCB, int mask)
result |= BUTTON4_PRESSED;
if (mask & RIGHTMOST_BUTTON_PRESSED) {
- switch (TCB->info.numbuttons) {
+ switch (CON.numButtons) {
case 1:
result |= BUTTON1_PRESSED;
break;
@@ -922,26 +1507,26 @@ decode_mouse(TERMINAL_CONTROL_BLOCK * TCB, int mask)
}
static int
-drv_twait(TERMINAL_CONTROL_BLOCK * TCB,
- int mode,
- int milliseconds,
- int *timeleft
- EVENTLIST_2nd(_nc_eventlist * evl))
+console_twait(
+ SCREEN *sp,
+ HANDLE fd,
+ int mode,
+ int milliseconds,
+ int *timeleft
+ EVENTLIST_2nd(_nc_eventlist * evl))
{
- SCREEN *sp;
INPUT_RECORD inp_rec;
BOOL b;
- DWORD nRead = 0, rc = -1;
+ DWORD nRead = 0, rc = (DWORD) (-1);
int code = 0;
FILETIME fstart;
FILETIME fend;
int diff;
bool isImmed = (milliseconds == 0);
-#define CONSUME() ReadConsoleInput(TCB->inp,&inp_rec,1,&nRead)
+#define CONSUME() ReadConsoleInput(fd,&inp_rec,1,&nRead)
- AssertTCB();
- SetSP();
+ assert(sp);
TR(TRACE_IEVENT, ("start twait: %d milliseconds, mode: %d",
milliseconds, mode));
@@ -953,19 +1538,19 @@ drv_twait(TERMINAL_CONTROL_BLOCK * TCB,
while (true) {
GetSystemTimeAsFileTime(&fstart);
- rc = WaitForSingleObject(TCB->inp, milliseconds);
+ rc = WaitForSingleObject(fd, (DWORD) milliseconds);
GetSystemTimeAsFileTime(&fend);
diff = (int) tdiff(fstart, fend);
milliseconds = Adjust(milliseconds, diff);
- if (!isImmed && milliseconds == 0)
+ if (!isImmed && milliseconds <= 0)
break;
if (rc == WAIT_OBJECT_0) {
if (mode) {
- b = GetNumberOfConsoleInputEvents(TCB->inp, &nRead);
+ b = GetNumberOfConsoleInputEvents(fd, &nRead);
if (b && nRead > 0) {
- b = PeekConsoleInput(TCB->inp, &inp_rec, 1, &nRead);
+ b = PeekConsoleInput(fd, &inp_rec, 1, &nRead);
if (b && nRead > 0) {
switch (inp_rec.EventType) {
case KEY_EVENT:
@@ -975,8 +1560,8 @@ drv_twait(TERMINAL_CONTROL_BLOCK * TCB,
if (inp_rec.Event.KeyEvent.bKeyDown) {
if (0 == ch) {
- int nKey = MapKey(TCB, vk);
- if ((nKey < 0) || FALSE == sp->_keypad_on) {
+ int nKey = MapKey(vk);
+ if (nKey < 0) {
CONSUME();
continue;
}
@@ -989,7 +1574,7 @@ drv_twait(TERMINAL_CONTROL_BLOCK * TCB,
}
continue;
case MOUSE_EVENT:
- if (decode_mouse(TCB,
+ if (decode_mouse(sp,
(inp_rec.Event.MouseEvent.dwButtonState
& BUTTON_MASK)) == 0) {
CONSUME();
@@ -998,9 +1583,10 @@ drv_twait(TERMINAL_CONTROL_BLOCK * TCB,
goto end;
}
continue;
+ /* e.g., FOCUS_EVENT */
default:
- SetConsoleActiveScreenBuffer(!PropOf(TCB)->progMode ?
- TCB->hdl : TCB->out);
+ CONSUME();
+ selectActiveHandle();
continue;
}
}
@@ -1028,16 +1614,35 @@ drv_twait(TERMINAL_CONTROL_BLOCK * TCB,
return code;
}
-static bool
-handle_mouse(TERMINAL_CONTROL_BLOCK * TCB, MOUSE_EVENT_RECORD mer)
+static int
+wcon_twait(TERMINAL_CONTROL_BLOCK * TCB,
+ int mode,
+ int milliseconds,
+ int *timeleft
+ EVENTLIST_2nd(_nc_eventlist * evl))
{
SCREEN *sp;
- MEVENT work;
- bool result = FALSE;
+ int code;
AssertTCB();
SetSP();
+ code = console_twait(sp,
+ CON.inp,
+ mode,
+ milliseconds,
+ timeleft EVENTLIST_2nd(_nc_eventlist * evl));
+ return code;
+}
+
+static bool
+handle_mouse(SCREEN *sp, MOUSE_EVENT_RECORD mer)
+{
+ MEVENT work;
+ bool result = FALSE;
+
+ assert(sp);
+
sp->_drv_mouse_old_buttons = sp->_drv_mouse_new_buttons;
sp->_drv_mouse_new_buttons = mer.dwButtonState & BUTTON_MASK;
@@ -1051,18 +1656,20 @@ handle_mouse(TERMINAL_CONTROL_BLOCK * TCB, MOUSE_EVENT_RECORD mer)
if (sp->_drv_mouse_new_buttons) {
- work.bstate |= decode_mouse(TCB, sp->_drv_mouse_new_buttons);
+ work.bstate |= (mmask_t) decode_mouse(sp, sp->_drv_mouse_new_buttons);
} else {
/* cf: BUTTON_PRESSED, BUTTON_RELEASED */
- work.bstate |= (decode_mouse(TCB, sp->_drv_mouse_old_buttons) >> 1);
+ work.bstate |= (mmask_t) (decode_mouse(sp,
+ sp->_drv_mouse_old_buttons)
+ >> 1);
result = TRUE;
}
work.x = mer.dwMousePosition.X;
- work.y = mer.dwMousePosition.Y;
+ work.y = mer.dwMousePosition.Y - AdjustY();
sp->_drv_mouse_fifo[sp->_drv_mouse_tail] = work;
sp->_drv_mouse_tail += 1;
@@ -1072,78 +1679,59 @@ handle_mouse(TERMINAL_CONTROL_BLOCK * TCB, MOUSE_EVENT_RECORD mer)
}
static int
-drv_read(TERMINAL_CONTROL_BLOCK * TCB, int *buf)
+wcon_read(TERMINAL_CONTROL_BLOCK * TCB, int *buf)
{
SCREEN *sp;
- int n = 1;
- INPUT_RECORD inp_rec;
- BOOL b;
- DWORD nRead;
- WORD vk;
- WORD sc;
+ int n;
AssertTCB();
assert(buf);
SetSP();
- memset(&inp_rec, 0, sizeof(inp_rec));
-
- T((T_CALLED("win32con::drv_read(%p)"), TCB));
- while ((b = ReadConsoleInput(TCB->inp, &inp_rec, 1, &nRead))) {
- if (b && nRead > 0) {
- if (inp_rec.EventType == KEY_EVENT) {
- if (!inp_rec.Event.KeyEvent.bKeyDown)
- continue;
- *buf = (int) inp_rec.Event.KeyEvent.uChar.AsciiChar;
- vk = inp_rec.Event.KeyEvent.wVirtualKeyCode;
- sc = inp_rec.Event.KeyEvent.wVirtualScanCode;
- if (*buf == 0) {
- if (sp->_keypad_on) {
- *buf = MapKey(TCB, vk);
- if (0 > (*buf))
- continue;
- else
- break;
- } else
- continue;
- } else { /* *buf != 0 */
- break;
- }
- } else if (inp_rec.EventType == MOUSE_EVENT) {
- if (handle_mouse(TCB, inp_rec.Event.MouseEvent)) {
- *buf = KEY_MOUSE;
- break;
- }
- }
- continue;
- }
- }
+ T((T_CALLED("win32con::wcon_read(%p)"), TCB));
+ n = _nc_mingw_console_read(sp, CON.inp, buf);
returnCode(n);
}
static int
-drv_nap(TERMINAL_CONTROL_BLOCK * TCB GCC_UNUSED, int ms)
+wcon_nap(TERMINAL_CONTROL_BLOCK * TCB GCC_UNUSED, int ms)
{
- Sleep(ms);
- return OK;
+ T((T_CALLED("win32con::wcon_nap(%p, %d)"), TCB, ms));
+ Sleep((DWORD) ms);
+ returnCode(OK);
+}
+
+static int
+wcon_cursorSet(TERMINAL_CONTROL_BLOCK * TCB GCC_UNUSED, int mode)
+{
+ int res = -1;
+ CONSOLE_CURSOR_INFO this_CI = CON.save_CI;
+ T((T_CALLED("win32con:wcon_cursorSet(%d)"), mode));
+ switch (mode) {
+ case 0:
+ this_CI.bVisible = FALSE;
+ break;
+ case 1:
+ break;
+ case 2:
+ this_CI.dwSize = 100;
+ break;
+ }
+ SetConsoleCursorInfo(CON.hdl, &this_CI);
+ returnCode(res);
}
static bool
-drv_kyExist(TERMINAL_CONTROL_BLOCK * TCB, int keycode)
+wcon_kyExist(TERMINAL_CONTROL_BLOCK * TCB GCC_UNUSED, int keycode)
{
- SCREEN *sp;
WORD nKey;
void *res;
bool found = FALSE;
LONG key = GenMap(0, (WORD) keycode);
- AssertTCB();
- SetSP();
-
- AssertTCB();
-
+ T((T_CALLED("win32con::wcon_kyExist(%d)"), keycode));
res = bsearch(&key,
- PropOf(TCB)->rmap,
+ CON.rmap,
(size_t) (N_INI + FKEYS),
sizeof(keylist[0]),
rkeycompare);
@@ -1153,26 +1741,29 @@ drv_kyExist(TERMINAL_CONTROL_BLOCK * TCB, int keycode)
if (!(nKey & 0x8000))
found = TRUE;
}
- return found;
+ returnCode(found);
}
static int
-drv_kpad(TERMINAL_CONTROL_BLOCK * TCB, bool flag GCC_UNUSED)
+wcon_kpad(TERMINAL_CONTROL_BLOCK * TCB, int flag GCC_UNUSED)
{
SCREEN *sp;
int code = ERR;
AssertTCB();
- sp = TCB->csp;
+ SetSP();
+ T((T_CALLED("win32con::wcon_kpad(%p, %d)"), TCB, flag));
if (sp) {
code = OK;
}
- return code;
+ returnCode(code);
}
static int
-drv_keyok(TERMINAL_CONTROL_BLOCK * TCB, int keycode, bool flag)
+wcon_keyok(TERMINAL_CONTROL_BLOCK * TCB,
+ int keycode,
+ int flag)
{
int code = ERR;
SCREEN *sp;
@@ -1181,12 +1772,14 @@ drv_keyok(TERMINAL_CONTROL_BLOCK * TCB, int keycode, bool flag)
void *res;
LONG key = GenMap(0, (WORD) keycode);
+ T((T_CALLED("win32con::wcon_keyok(%p, %d, %d)"), TCB, keycode, flag));
+
AssertTCB();
SetSP();
if (sp) {
res = bsearch(&key,
- PropOf(TCB)->rmap,
+ CON.rmap,
(size_t) (N_INI + FKEYS),
sizeof(keylist[0]),
rkeycompare);
@@ -1199,43 +1792,438 @@ drv_keyok(TERMINAL_CONTROL_BLOCK * TCB, int keycode, bool flag)
*(LONG *) res = GenMap(vKey, nKey);
}
}
- return code;
+ returnCode(code);
}
NCURSES_EXPORT_VAR (TERM_DRIVER) _nc_WIN_DRIVER = {
FALSE,
- drv_CanHandle, /* CanHandle */
- drv_init, /* init */
- drv_release, /* release */
- drv_size, /* size */
- drv_sgmode, /* sgmode */
- drv_conattr, /* conattr */
- drv_mvcur, /* hwcur */
- drv_mode, /* mode */
- drv_rescol, /* rescol */
- drv_rescolors, /* rescolors */
- drv_setcolor, /* color */
- drv_dobeepflash, /* DoBeepFlash */
- drv_initpair, /* initpair */
- drv_initcolor, /* initcolor */
- drv_do_color, /* docolor */
- drv_initmouse, /* initmouse */
- drv_testmouse, /* testmouse */
- drv_setfilter, /* setfilter */
- drv_hwlabel, /* hwlabel */
- drv_hwlabelOnOff, /* hwlabelOnOff */
- drv_doupdate, /* update */
- drv_defaultcolors, /* defaultcolors */
- drv_print, /* print */
- drv_size, /* getsize */
- drv_setsize, /* setsize */
- drv_initacs, /* initacs */
- drv_screen_init, /* scinit */
- drv_wrap, /* scexit */
- drv_twait, /* twait */
- drv_read, /* read */
- drv_nap, /* nap */
- drv_kpad, /* kpad */
- drv_keyok, /* kyOk */
- drv_kyExist /* kyExist */
+ wcon_name, /* Name */
+ wcon_CanHandle, /* CanHandle */
+ wcon_init, /* init */
+ wcon_release, /* release */
+ wcon_size, /* size */
+ wcon_sgmode, /* sgmode */
+ wcon_conattr, /* conattr */
+ wcon_mvcur, /* hwcur */
+ wcon_mode, /* mode */
+ wcon_rescol, /* rescol */
+ wcon_rescolors, /* rescolors */
+ wcon_setcolor, /* color */
+ wcon_dobeepflash, /* DoBeepFlash */
+ wcon_initpair, /* initpair */
+ wcon_initcolor, /* initcolor */
+ wcon_do_color, /* docolor */
+ wcon_initmouse, /* initmouse */
+ wcon_testmouse, /* testmouse */
+ wcon_setfilter, /* setfilter */
+ wcon_hwlabel, /* hwlabel */
+ wcon_hwlabelOnOff, /* hwlabelOnOff */
+ wcon_doupdate, /* update */
+ wcon_defaultcolors, /* defaultcolors */
+ wcon_print, /* print */
+ wcon_size, /* getsize */
+ wcon_setsize, /* setsize */
+ wcon_initacs, /* initacs */
+ wcon_screen_init, /* scinit */
+ wcon_wrap, /* scexit */
+ wcon_twait, /* twait */
+ wcon_read, /* read */
+ wcon_nap, /* nap */
+ wcon_kpad, /* kpad */
+ wcon_keyok, /* kyOk */
+ wcon_kyExist, /* kyExist */
+ wcon_cursorSet /* cursorSet */
};
+
+/* --------------------------------------------------------- */
+
+static HANDLE
+get_handle(int fd)
+{
+ intptr_t value = _get_osfhandle(fd);
+ return (HANDLE) value;
+}
+
+#if WINVER >= 0x0600
+/* This function tests, whether or not the ncurses application
+ is running as a descendant of MSYS2/cygwin mintty terminal
+ application. mintty doesn't use Windows Console for it's screen
+ I/O, so the native Windows _isatty doesn't recognize it as
+ character device. But we can discover we are at the end of an
+ Pipe and can query to server side of the pipe, looking whether
+ or not this is mintty.
+ */
+static int
+_ismintty(int fd, LPHANDLE pMinTTY)
+{
+ HANDLE handle = get_handle(fd);
+ DWORD dw;
+ int code = 0;
+
+ T((T_CALLED("win32con::_ismintty(%d, %p)"), fd, pMinTTY));
+
+ if (handle != INVALID_HANDLE_VALUE) {
+ dw = GetFileType(handle);
+ if (dw == FILE_TYPE_PIPE) {
+ if (GetNamedPipeInfo(handle, 0, 0, 0, 0)) {
+ ULONG pPid;
+ /* Requires NT6 */
+ if (GetNamedPipeServerProcessId(handle, &pPid)) {
+ TCHAR buf[MAX_PATH];
+ DWORD len = 0;
+ /* These security attributes may allow us to
+ create a remote thread in mintty to manipulate
+ the terminal state remotely */
+ HANDLE pHandle = OpenProcess(
+ PROCESS_CREATE_THREAD
+ | PROCESS_QUERY_INFORMATION
+ | PROCESS_VM_OPERATION
+ | PROCESS_VM_WRITE
+ | PROCESS_VM_READ,
+ FALSE,
+ pPid);
+ if (pMinTTY)
+ *pMinTTY = INVALID_HANDLE_VALUE;
+ if (pHandle != INVALID_HANDLE_VALUE) {
+ if ((len = GetProcessImageFileName(
+ pHandle,
+ buf,
+ (DWORD)
+ array_length(buf)))) {
+ TCHAR *pos = _tcsrchr(buf, _T('\\'));
+ if (pos) {
+ pos++;
+ if (_tcsnicmp(pos, _TEXT("mintty.exe"), 10)
+ == 0) {
+ if (pMinTTY)
+ *pMinTTY = pHandle;
+ code = 1;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ returnCode(code);
+}
+#endif
+
+/* Borrowed from ansicon project.
+ Check whether or not an I/O handle is associated with
+ a Windows console.
+*/
+static BOOL
+IsConsoleHandle(HANDLE hdl)
+{
+ DWORD dwFlag = 0;
+ BOOL result;
+
+ if (!GetConsoleMode(hdl, &dwFlag)) {
+ result = (int) WriteConsoleA(hdl, NULL, 0, &dwFlag, NULL);
+ } else {
+ result = (int) (dwFlag & ENABLE_PROCESSED_OUTPUT);
+ }
+ return result;
+}
+
+/* Our replacement for the systems _isatty to include also
+ a test for mintty. This is called from the NC_ISATTY macro
+ defined in curses.priv.h
+ */
+int
+_nc_mingw_isatty(int fd)
+{
+ int result = 0;
+
+#ifdef __MING32__
+#define SysISATTY(fd) _isatty(fd)
+#else
+#define SysISATTY(fd) isatty(fd)
+#endif
+ if (SysISATTY(fd)) {
+ result = 1;
+ } else {
+#if WINVER >= 0x0600
+ result = _ismintty(fd, NULL);
+#endif
+ }
+ return result;
+}
+
+/* This is used when running in terminfo mode to discover,
+ whether or not the "terminal" is actually a Windows
+ Console. It's the responsibilty of the console to deal
+ with the terminal escape sequences that are sent by
+ terminfo.
+ */
+int
+_nc_mingw_isconsole(int fd)
+{
+ HANDLE hdl = get_handle(fd);
+ int code = 0;
+
+ T((T_CALLED("win32con::_nc_mingw_isconsole(%d)"), fd));
+
+ code = (int) IsConsoleHandle(hdl);
+
+ returnCode(code);
+}
+
+#define TC_PROLOGUE(fd) \
+ SCREEN *sp; \
+ TERMINAL *term = 0; \
+ int code = ERR; \
+ if (_nc_screen_chain == 0) \
+ return 0; \
+ for (each_screen(sp)) { \
+ if (sp->_term && (sp->_term->Filedes == fd)) { \
+ term = sp->_term; \
+ break; \
+ } \
+ } \
+ assert(term != 0)
+
+int
+_nc_mingw_tcsetattr(
+ int fd,
+ int optional_action GCC_UNUSED,
+ const struct termios *arg)
+{
+ TC_PROLOGUE(fd);
+
+ if (_nc_mingw_isconsole(fd)) {
+ DWORD dwFlag = 0;
+ HANDLE ofd = get_handle(fd);
+ if (ofd != INVALID_HANDLE_VALUE) {
+ if (arg) {
+ if (arg->c_lflag & ICANON)
+ dwFlag |= ENABLE_LINE_INPUT;
+ else
+ dwFlag = dwFlag & (DWORD) (~ENABLE_LINE_INPUT);
+
+ if (arg->c_lflag & ECHO)
+ dwFlag = dwFlag | ENABLE_ECHO_INPUT;
+ else
+ dwFlag = dwFlag & (DWORD) (~ENABLE_ECHO_INPUT);
+
+ if (arg->c_iflag & BRKINT)
+ dwFlag |= ENABLE_PROCESSED_INPUT;
+ else
+ dwFlag = dwFlag & (DWORD) (~ENABLE_PROCESSED_INPUT);
+ }
+ dwFlag |= ENABLE_MOUSE_INPUT;
+ SetConsoleMode(ofd, dwFlag);
+ code = OK;
+ }
+ }
+ if (arg)
+ term->Nttyb = *arg;
+
+ return code;
+}
+
+int
+_nc_mingw_tcgetattr(int fd, struct termios *arg)
+{
+ TC_PROLOGUE(fd);
+
+ if (_nc_mingw_isconsole(fd)) {
+ if (arg)
+ *arg = term->Nttyb;
+ }
+ return code;
+}
+
+int
+_nc_mingw_tcflush(int fd, int queue)
+{
+ TC_PROLOGUE(fd);
+ (void) term;
+
+ if (_nc_mingw_isconsole(fd)) {
+ if (queue == TCIFLUSH) {
+ BOOL b = FlushConsoleInputBuffer(GetStdHandle(STD_INPUT_HANDLE));
+ if (!b)
+ return (int) GetLastError();
+ }
+ }
+ return code;
+}
+
+int
+_nc_mingw_testmouse(
+ SCREEN *sp,
+ HANDLE fd,
+ int delay)
+{
+ int rc = 0;
+
+ assert(sp);
+
+ if (sp->_drv_mouse_head < sp->_drv_mouse_tail) {
+ rc = TW_MOUSE;
+ } else {
+ rc = console_twait(sp,
+ fd,
+ TWAIT_MASK,
+ delay,
+ (int *) 0
+ EVENTLIST_2nd(evl));
+ }
+ return rc;
+}
+
+int
+_nc_mingw_console_read(
+ SCREEN *sp,
+ HANDLE fd,
+ int *buf)
+{
+ int n = 1;
+ INPUT_RECORD inp_rec;
+ BOOL b;
+ DWORD nRead;
+ WORD vk;
+
+ assert(sp);
+ assert(buf);
+
+ memset(&inp_rec, 0, sizeof(inp_rec));
+
+ T((T_CALLED("_nc_mingw_console_read(%p)"), sp));
+
+ while ((b = ReadConsoleInput(fd, &inp_rec, 1, &nRead))) {
+ if (b && nRead > 0) {
+ if (inp_rec.EventType == KEY_EVENT) {
+ if (!inp_rec.Event.KeyEvent.bKeyDown)
+ continue;
+ *buf = (int) inp_rec.Event.KeyEvent.uChar.AsciiChar;
+ vk = inp_rec.Event.KeyEvent.wVirtualKeyCode;
+ /*
+ * There are 24 virtual function-keys, and typically
+ * 12 function-keys on a keyboard. Use the shift-modifier
+ * to provide the remaining 12 keys.
+ */
+ if (vk >= VK_F1 && vk <= VK_F12) {
+ if (inp_rec.Event.KeyEvent.dwControlKeyState & SHIFT_PRESSED) {
+ vk = (WORD) (vk + 12);
+ }
+ }
+ if (*buf == 0) {
+ int key = MapKey(vk);
+ if (key < 0)
+ continue;
+ if (sp->_keypad_on) {
+ *buf = key;
+ } else {
+ ungetch('\0');
+ *buf = AnsiKey(vk);
+ }
+ }
+ break;
+ } else if (inp_rec.EventType == MOUSE_EVENT) {
+ if (handle_mouse(sp,
+ inp_rec.Event.MouseEvent)) {
+ *buf = KEY_MOUSE;
+ break;
+ }
+ }
+ continue;
+ }
+ }
+ returnCode(n);
+}
+
+static
+__attribute__((constructor))
+ void _enter_console(void)
+{
+ if (!console_initialized) {
+ int i;
+ DWORD num_buttons;
+ WORD a;
+ BOOL buffered = TRUE;
+ BOOL b;
+
+ START_TRACE();
+ if (_nc_mingw_isatty(0)) {
+ CON.isMinTTY = TRUE;
+ }
+
+ for (i = 0; i < (N_INI + FKEYS); i++) {
+ if (i < N_INI) {
+ CON.rmap[i] = CON.map[i] =
+ (DWORD) keylist[i];
+ CON.ansi_map[i] = (DWORD) ansi_keys[i];
+ } else {
+ CON.rmap[i] = CON.map[i] =
+ (DWORD) GenMap((VK_F1 + (i - N_INI)),
+ (KEY_F(1) + (i - N_INI)));
+ CON.ansi_map[i] =
+ (DWORD) GenMap((VK_F1 + (i - N_INI)),
+ (';' + (i - N_INI)));
+ }
+ }
+ qsort(CON.ansi_map,
+ (size_t) (MAPSIZE),
+ sizeof(keylist[0]),
+ keycompare);
+ qsort(CON.map,
+ (size_t) (MAPSIZE),
+ sizeof(keylist[0]),
+ keycompare);
+ qsort(CON.rmap,
+ (size_t) (MAPSIZE),
+ sizeof(keylist[0]),
+ rkeycompare);
+
+ if (GetNumberOfConsoleMouseButtons(&num_buttons)) {
+ CON.numButtons = (int) num_buttons;
+ } else {
+ CON.numButtons = 1;
+ }
+
+ a = MapColor(true, COLOR_WHITE) | MapColor(false, COLOR_BLACK);
+ for (i = 0; i < NUMPAIRS; i++)
+ CON.pairs[i] = a;
+
+ CON.inp = GetStdHandle(STD_INPUT_HANDLE);
+ CON.out = GetStdHandle(STD_OUTPUT_HANDLE);
+
+ b = AllocConsole();
+
+ if (!b)
+ b = AttachConsole(ATTACH_PARENT_PROCESS);
+
+ if (getenv("NCGDB") || getenv("NCURSES_CONSOLE2")) {
+ T(("... will not buffer console"));
+ buffered = FALSE;
+ CON.hdl = CON.out;
+ } else {
+ T(("... creating console buffer"));
+ CON.hdl = CreateConsoleScreenBuffer(GENERIC_READ | GENERIC_WRITE,
+ 0,
+ NULL,
+ CONSOLE_TEXTMODE_BUFFER,
+ NULL);
+ }
+
+ if (CON.hdl != INVALID_HANDLE_VALUE) {
+ CON.buffered = buffered;
+ get_SBI();
+ CON.save_SBI = CON.SBI;
+ if (!buffered) {
+ save_original_screen();
+ set_scrollback(FALSE, &CON.SBI);
+ }
+ GetConsoleCursorInfo(CON.hdl, &CON.save_CI);
+ T(("... initial cursor is %svisible, %d%%",
+ (CON.save_CI.bVisible ? "" : "not-"),
+ (int) CON.save_CI.dwSize));
+ }
+
+ console_initialized = TRUE;
+ }
+}