X-Git-Url: https://ncurses.scripts.mit.edu/?a=blobdiff_plain;f=ncurses%2Fwin32con%2Fwin_driver.c;h=2425b3a44ce6f21eb2261d2a73a2cc4bf64b60ee;hb=HEAD;hp=0cb27e81b3f8a0c43466185e6c3bd3d591367efd;hpb=1bab6fd2bd6c65560d26b46b0a245bd7d46f2add;p=ncurses.git diff --git a/ncurses/win32con/win_driver.c b/ncurses/win32con/win_driver.c index 0cb27e81..2425b3a4 100644 --- a/ncurses/win32con/win_driver.c +++ b/ncurses/win32con/win_driver.c @@ -1,5 +1,6 @@ /**************************************************************************** - * Copyright (c) 1998-2013,2014 Free Software Foundation, Inc. * + * Copyright 2018-2021,2023 Thomas E. Dickey * + * Copyright 2008-2016,2017 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 * @@ -34,22 +35,31 @@ /* * 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 + +#ifdef _WIN32 #include +#else +#include +#include +#endif + #include #define PSAPI_VERSION 2 #include -#define CUR my_term.type. +#define CUR TerminalType(my_term). -MODULE_ID("$Id: win_driver.c,v 1.39 2014/06/29 22:48:17 tom Exp $") +#define CONTROL_PRESSED (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED) -#ifndef __GNUC__ -# error We need GCC to compile for MinGW -#endif +MODULE_ID("$Id: win_driver.c,v 1.74 2023/09/16 16:27:44 tom Exp $") + +#define TypeAlloca(type,count) (type*) _alloca(sizeof(type) * (size_t) (count)) #define WINMAGIC NCDRV_MAGIC(NCDRV_WINCONSOLE) @@ -57,7 +67,8 @@ MODULE_ID("$Id: win_driver.c,v 1.39 2014/06/29 22:48:17 tom Exp $") #define array_length(a) (sizeof(a)/sizeof(a[0])) -#define okConsoleHandle(TCB) (TCB != 0 && CON.hdl != INVALID_HANDLE_VALUE) +static bool InitConsole(void); +static bool okConsoleHandle(TERMINAL_CONTROL_BLOCK *); #define AssertTCB() assert(TCB != 0 && (TCB->magic == WINMAGIC)) #define SetSP() assert(TCB->csp != 0); sp = TCB->csp; (void) sp @@ -66,46 +77,72 @@ MODULE_ID("$Id: win_driver.c,v 1.39 2014/06/29 22:48:17 tom Exp $") #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 +/* *INDENT-OFF* */ static const LONG keylist[] = { - GenMap(VK_PRIOR, KEY_PPAGE), - GenMap(VK_NEXT, KEY_NPAGE), - GenMap(VK_END, KEY_END), - GenMap(VK_HOME, KEY_HOME), - GenMap(VK_LEFT, KEY_LEFT), - GenMap(VK_UP, KEY_UP), - GenMap(VK_RIGHT, KEY_RIGHT), - GenMap(VK_DOWN, KEY_DOWN), + GenMap(VK_PRIOR, KEY_PPAGE), + GenMap(VK_NEXT, KEY_NPAGE), + GenMap(VK_END, KEY_END), + GenMap(VK_HOME, KEY_HOME), + GenMap(VK_LEFT, KEY_LEFT), + GenMap(VK_UP, KEY_UP), + GenMap(VK_RIGHT, KEY_RIGHT), + GenMap(VK_DOWN, KEY_DOWN), GenMap(VK_DELETE, KEY_DC), GenMap(VK_INSERT, KEY_IC) }; +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') +}; +/* *INDENT-ON* */ #define N_INI ((int)array_length(keylist)) #define FKEYS 24 #define MAPSIZE (FKEYS + N_INI) #define NUMPAIRS 64 -/* A process can only have a single console, so it's save +/* A process can only have a single console, so it is safe to maintain all the information about it in a single - static scructure. + 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]; 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; static BOOL console_initialized = FALSE; @@ -125,6 +162,11 @@ MapColor(bool fore, int color) return (WORD) a; } +#define RevAttr(attr) \ + (WORD) (((attr) & 0xff00) | \ + ((((attr) & 0x07) << 4) | \ + (((attr) & 0x70) >> 4))) + static WORD MapAttr(WORD res, attr_t ch) { @@ -140,16 +182,11 @@ MapAttr(WORD res, attr_t ch) } if (ch & A_REVERSE) { - res = (WORD) ((res & 0xff00) | - (((res & 0x07) << 4) | - ((res & 0x70) >> 4))); + res = RevAttr(res); } if (ch & A_STANDOUT) { - res = (WORD) ((res & 0xff00) | - (((res & 0x07) << 4) | - ((res & 0x70) >> 4)) | - BACKGROUND_INTENSITY); + res = RevAttr(res) | BACKGROUND_INTENSITY; } if (ch & A_BOLD) @@ -161,19 +198,71 @@ MapAttr(WORD res, attr_t 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: check wcwidth of base character, fill if needed for double-width * TODO: _nc_wacs should be part of sp. */ static BOOL con_write16(TERMINAL_CONTROL_BLOCK * TCB, int y, int x, cchar_t *str, int limit) { int actual = 0; - CHAR_INFO ci[limit]; + CHAR_INFO *ci = TypeAlloca(CHAR_INFO, limit); COORD loc, siz; SMALL_RECT rec; int i; @@ -205,24 +294,24 @@ con_write16(TERMINAL_CONTROL_BLOCK * TCB, int y, int x, cchar_t *str, int limit) ++actual; } - loc.X = (short) 0; - loc.Y = (short) 0; - siz.X = (short) actual; + loc.X = (SHORT) 0; + loc.Y = (SHORT) 0; + siz.X = (SHORT) actual; siz.Y = 1; - rec.Left = (short) x; + rec.Left = (SHORT) x; rec.Top = (SHORT) (y + AdjustY()); - rec.Right = (short) (x + limit - 1); + rec.Right = (SHORT) (x + limit - 1); rec.Bottom = rec.Top; - return WriteConsoleOutputW(CON.hdl, ci, siz, loc, &rec); + 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]; + CHAR_INFO *ci = TypeAlloca(CHAR_INFO, n); COORD loc, siz; SMALL_RECT rec; int i; @@ -254,7 +343,7 @@ con_write8(TERMINAL_CONTROL_BLOCK * TCB, int y, int x, chtype *str, int n) rec.Right = (short) (x + n - 1); rec.Bottom = rec.Top; - return WriteConsoleOutput(CON.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 @@ -351,34 +440,31 @@ static bool restore_original_screen(void) { COORD bufferCoord; - SMALL_RECT writeRegion; bool result = FALSE; + SMALL_RECT save_region = CON.save_region; - if (CON.window_only) { - writeRegion.Top = CON.SBI.srWindow.Top; - writeRegion.Left = CON.SBI.srWindow.Left; - writeRegion.Bottom = CON.SBI.srWindow.Bottom; - writeRegion.Right = CON.SBI.srWindow.Right; - T(("... restoring window")); - } else { - writeRegion.Top = 0; - writeRegion.Left = 0; - writeRegion.Bottom = (SHORT) (CON.SBI.dwSize.Y - 1); - writeRegion.Right = (SHORT) (CON.SBI.dwSize.X - 1); - T(("... restoring entire buffer")); - } + T(("... restoring %s", CON.window_only ? "window" : "entire buffer")); - bufferCoord.X = bufferCoord.Y = 0; + bufferCoord.X = (SHORT) (CON.window_only ? CON.SBI.srWindow.Left : 0); + bufferCoord.Y = (SHORT) (CON.window_only ? CON.SBI.srWindow.Top : 0); - if (WriteConsoleOutput(CON.hdl, - CON.save_screen, - CON.SBI.dwSize, - bufferCoord, - &writeRegion)) { + 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")); } - T(("... restore original screen contents %s", result ? "ok" : "err")); return result; } @@ -396,20 +482,35 @@ wcon_doupdate(TERMINAL_CONTROL_BLOCK * TCB) int y, nonempty, n, x0, x1, Width, Height; SCREEN *sp; - AssertTCB(); - SetSP(); - T((T_CALLED("win32con::wcon_doupdate(%p)"), TCB)); if (okConsoleHandle(TCB)) { + SetSP(); Width = screen_columns(sp); Height = screen_lines(sp); - nonempty = min(Height, NewScreen(sp)->_maxy + 1); + nonempty = Min(Height, NewScreen(sp)->_maxy + 1); + + T(("... %dx%d clear cur:%d new:%d", + Height, Width, + CurScreen(sp)->_clear, + NewScreen(sp)->_clear)); + + if (SP_PARM->_endwin == ewSuspend) { + + 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 = ewRunning; + } if ((CurScreen(sp)->_clear || NewScreen(sp)->_clear)) { int x; #if USE_WIDEC_SUPPORT - cchar_t empty[Width]; + cchar_t *empty = TypeAlloca(cchar_t, Width); wchar_t blank[2] = { L' ', L'\0' @@ -418,7 +519,7 @@ wcon_doupdate(TERMINAL_CONTROL_BLOCK * TCB) for (x = 0; x < Width; x++) setcchar(&empty[x], blank, 0, 0, 0); #else - chtype empty[Width]; + chtype *empty = TypeAlloca(chtype, Width); for (x = 0; x < Width; x++) empty[x] = ' '; @@ -433,6 +534,8 @@ wcon_doupdate(TERMINAL_CONTROL_BLOCK * TCB) 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++) { @@ -509,6 +612,12 @@ wcon_doupdate(TERMINAL_CONTROL_BLOCK * TCB) returnCode(result); } +#ifdef __MING32__ +#define SysISATTY(fd) _isatty(fd) +#else +#define SysISATTY(fd) isatty(fd) +#endif + static bool wcon_CanHandle(TERMINAL_CONTROL_BLOCK * TCB, const char *tname, @@ -540,14 +649,19 @@ wcon_CanHandle(TERMINAL_CONTROL_BLOCK * TCB, } } else if (tname != 0 && stricmp(tname, "unknown") == 0) { code = TRUE; + } else if (SysISATTY(TCB->term.Filedes)) { + code = TRUE; } /* * This is intentional, to avoid unnecessary breakage of applications * using symbols. */ - if (code && (TCB->term.type.Booleans == 0)) { - _nc_init_termtype(&(TCB->term.type)); + if (code && (TerminalType(&TCB->term).Booleans == 0)) { + _nc_init_termtype(&TerminalType(&TCB->term)); +#if NCURSES_EXT_NUMBERS + _nc_export_termtype2(&TCB->term.type, &TerminalType(&TCB->term)); +#endif } if (!code) { @@ -559,14 +673,59 @@ wcon_CanHandle(TERMINAL_CONTROL_BLOCK * TCB, static int wcon_dobeepflash(TERMINAL_CONTROL_BLOCK * TCB, - int beepFlag GCC_UNUSED) + int beepFlag) { SCREEN *sp; int res = ERR; - AssertTCB(); - SetSP(); + 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 = TypeAlloca(CHAR_INFO, max_cells); + CHAR_INFO *that_screen = TypeAlloca(CHAR_INFO, max_cells); + COORD this_size; + SMALL_RECT this_region; + COORD bufferCoord; + if (okConsoleHandle(TCB)) { + 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(CHAR_INFO) * (size_t) max_cells); + + 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 */ + } + res = OK; + } return res; } @@ -637,8 +796,6 @@ wcon_setcolor(TERMINAL_CONTROL_BLOCK * TCB, int color, int (*outc) (SCREEN *, int) GCC_UNUSED) { - AssertTCB(); - if (okConsoleHandle(TCB)) { WORD a = MapColor(fore, color); a |= (WORD) ((CON.SBI.wAttributes) & (fore ? 0xfff8 : 0xff8f)); @@ -652,7 +809,6 @@ wcon_rescol(TERMINAL_CONTROL_BLOCK * TCB) { bool res = FALSE; - AssertTCB(); if (okConsoleHandle(TCB)) { WORD a = FOREGROUND_BLUE | FOREGROUND_RED | FOREGROUND_GREEN; SetConsoleTextAttribute(CON.hdl, a); @@ -679,8 +835,6 @@ wcon_size(TERMINAL_CONTROL_BLOCK * TCB, int *Lines, int *Cols) { int result = ERR; - AssertTCB(); - T((T_CALLED("win32con::wcon_size(%p)"), TCB)); if (okConsoleHandle(TCB) && @@ -715,65 +869,143 @@ wcon_sgmode(TERMINAL_CONTROL_BLOCK * TCB, int setFlag, TTY * buf) DWORD dwFlag = 0; tcflag_t iflag; tcflag_t lflag; + int result = ERR; - AssertTCB(); + if (buf != NULL && okConsoleHandle(TCB)) { + + if (setFlag) { + iflag = buf->c_iflag; + lflag = buf->c_lflag; + + GetConsoleMode(CON.inp, &dwFlag); + + if (lflag & ICANON) + dwFlag |= ENABLE_LINE_INPUT; + else + dwFlag &= (DWORD) (~ENABLE_LINE_INPUT); - if (TCB == 0 || buf == NULL) - return ERR; + if (lflag & ECHO) + dwFlag |= ENABLE_ECHO_INPUT; + else + dwFlag &= (DWORD) (~ENABLE_ECHO_INPUT); - if (setFlag) { - iflag = buf->c_iflag; - lflag = buf->c_lflag; + if (iflag & BRKINT) + dwFlag |= ENABLE_PROCESSED_INPUT; + else + dwFlag &= (DWORD) (~ENABLE_PROCESSED_INPUT); + + dwFlag |= ENABLE_MOUSE_INPUT; + + buf->c_iflag = iflag; + buf->c_lflag = lflag; + SetConsoleMode(CON.inp, dwFlag); + TCB->term.Nttyb = *buf; + } else { + iflag = TCB->term.Nttyb.c_iflag; + lflag = TCB->term.Nttyb.c_lflag; + GetConsoleMode(CON.inp, &dwFlag); + + if (dwFlag & ENABLE_LINE_INPUT) + lflag |= ICANON; + else + lflag &= (tcflag_t) (~ICANON); - GetConsoleMode(CON.inp, &dwFlag); + if (dwFlag & ENABLE_ECHO_INPUT) + lflag |= ECHO; + else + lflag &= (tcflag_t) (~ECHO); - if (lflag & ICANON) - dwFlag |= ENABLE_LINE_INPUT; - else - dwFlag &= (DWORD) (~ENABLE_LINE_INPUT); + if (dwFlag & ENABLE_PROCESSED_INPUT) + iflag |= BRKINT; + else + iflag &= (tcflag_t) (~BRKINT); - if (lflag & ECHO) - dwFlag |= ENABLE_ECHO_INPUT; - else - dwFlag &= (DWORD) (~ENABLE_ECHO_INPUT); + TCB->term.Nttyb.c_iflag = iflag; + TCB->term.Nttyb.c_lflag = lflag; - if (iflag & BRKINT) - dwFlag |= ENABLE_PROCESSED_INPUT; - else - dwFlag &= (DWORD) (~ENABLE_PROCESSED_INPUT); + *buf = TCB->term.Nttyb; + } + result = OK; + } + return result; +} - dwFlag |= ENABLE_MOUSE_INPUT; +#define MIN_WIDE 80 +#define MIN_HIGH 24 - buf->c_iflag = iflag; - buf->c_lflag = lflag; - SetConsoleMode(CON.inp, dwFlag); - TCB->term.Nttyb = *buf; +/* + * 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 { - iflag = TCB->term.Nttyb.c_iflag; - lflag = TCB->term.Nttyb.c_lflag; - GetConsoleMode(CON.inp, &dwFlag); + int high = info->srWindow.Bottom - info->srWindow.Top + 1; + int wide = info->srWindow.Right - info->srWindow.Left + 1; - if (dwFlag & ENABLE_LINE_INPUT) - lflag |= ICANON; - else - lflag &= (tcflag_t) (~ICANON); + 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; + } - if (dwFlag & ENABLE_ECHO_INPUT) - lflag |= ECHO; - else - lflag &= (tcflag_t) (~ECHO); + rect.Left = + rect.Top = 0; + rect.Right = (SHORT) (wide - 1); + rect.Bottom = (SHORT) (high - 1); - if (dwFlag & ENABLE_PROCESSED_INPUT) - iflag |= BRKINT; - else - iflag &= (tcflag_t) (~BRKINT); + coord.X = (SHORT) wide; + coord.Y = (SHORT) high; - TCB->term.Nttyb.c_iflag = iflag; - TCB->term.Nttyb.c_lflag = lflag; + if (info->dwSize.Y != high || + info->dwSize.X != wide || + info->srWindow.Top != 0 || + info->srWindow.Left != 0) { + changed = TRUE; + } - *buf = TCB->term.Nttyb; } - return OK; + + 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 @@ -783,51 +1015,60 @@ wcon_mode(TERMINAL_CONTROL_BLOCK * TCB, int progFlag, int defFlag) TERMINAL *_term = (TERMINAL *) TCB; int code = ERR; - AssertTCB(); - sp = TCB->csp; - - 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 ((wcon_sgmode(TCB, FALSE, &(_term->Nttyb)) == OK)) { - _term->Nttyb.c_oflag &= (tcflag_t) (~OFLAGS_TABS); - code = OK; + if (okConsoleHandle(TCB)) { + sp = TCB->csp; + + 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 ((wcon_sgmode(TCB, FALSE, &(_term->Nttyb)) == OK)) { + _term->Nttyb.c_oflag &= (tcflag_t) (~OFLAGS_TABS); + code = OK; + } + } else { + /* reset_prog_mode */ + if (wcon_sgmode(TCB, TRUE, &(_term->Nttyb)) == OK) { + if (sp) { + if (sp->_keypad_on) + _nc_keypad(sp, TRUE); + } + if (!CON.buffered) { + set_scrollback(FALSE, &CON.SBI); + } + code = OK; + } } - } else { - /* reset_prog_mode */ - if (wcon_sgmode(TCB, TRUE, &(_term->Nttyb)) == OK) { + T(("... buffered:%d, clear:%d", CON.buffered, CurScreen(sp)->_clear)); + } else { /* shell mode */ + if (defFlag) { + /* def_shell_mode */ + if (wcon_sgmode(TCB, FALSE, &(_term->Ottyb)) == OK) { + code = OK; + } + } else { + /* reset_shell_mode */ if (sp) { - if (sp->_keypad_on) - _nc_keypad(sp, TRUE); + _nc_keypad(sp, FALSE); + NCURSES_SP_NAME(_nc_flush) (sp); } - code = OK; - } - } - } else { /* shell mode */ - if (defFlag) { - /* def_shell_mode */ - if (wcon_sgmode(TCB, FALSE, &(_term->Ottyb)) == OK) { - code = OK; - } - } else { - /* reset_shell_mode */ - if (sp) { - _nc_keypad(sp, FALSE); - NCURSES_SP_NAME(_nc_flush) (sp); - } - code = wcon_sgmode(TCB, TRUE, &(_term->Ottyb)); - if (!CON.buffered) { - if (!restore_original_screen()) - code = ERR; + 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 @@ -881,6 +1122,29 @@ MapKey(WORD vKey) return code; } +static int +AnsiKey(WORD vKey) +{ + WORD nKey = 0; + void *res; + LONG key = GenMap(vKey, 0); + int code = -1; + + res = bsearch(&key, + CON.ansi_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 void wcon_release(TERMINAL_CONTROL_BLOCK * TCB) { @@ -893,85 +1157,79 @@ wcon_release(TERMINAL_CONTROL_BLOCK * TCB) returnVoid; } -/* - * 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. - */ static bool -save_original_screen(void) +read_screen_data(void) { bool result = FALSE; - COORD bufferSize; COORD bufferCoord; - SMALL_RECT readRegion; size_t want; - bufferSize.X = CON.SBI.dwSize.X; - bufferSize.Y = CON.SBI.dwSize.Y; - want = (size_t) (bufferSize.X * bufferSize.Y); + 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 = bufferCoord.Y = 0; - - readRegion.Top = 0; - readRegion.Left = 0; - readRegion.Bottom = (SHORT) (bufferSize.Y - 1); - readRegion.Right = (SHORT) (bufferSize.X - 1); - - T(("... reading console buffer %dx%d into %d,%d - %d,%d at %d,%d", - bufferSize.Y, bufferSize.X, - readRegion.Top, - readRegion.Left, - readRegion.Bottom, - readRegion.Right, + 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 (ReadConsoleOutput(CON.hdl, - CON.save_screen, - bufferSize, - bufferCoord, - &readRegion)) { + 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); + } + } - bufferSize.X = (SHORT) (CON.SBI.srWindow.Right - - CON.SBI.srWindow.Left + 1); - bufferSize.Y = (SHORT) (CON.SBI.srWindow.Bottom - - CON.SBI.srWindow.Top + 1); - want = (size_t) (bufferSize.X * bufferSize.Y); - - if ((CON.save_screen = malloc(want * sizeof(CHAR_INFO))) != 0) { - bufferCoord.X = bufferCoord.Y = 0; - - readRegion.Top = CON.SBI.srWindow.Top; - readRegion.Left = CON.SBI.srWindow.Left; - readRegion.Bottom = CON.SBI.srWindow.Bottom; - readRegion.Right = CON.SBI.srWindow.Right; - - T(("... reading console window %dx%d into %d,%d - %d,%d at %d,%d", - bufferSize.Y, bufferSize.X, - readRegion.Top, - readRegion.Left, - readRegion.Bottom, - readRegion.Right, - bufferCoord.Y, - bufferCoord.X)); - - if (ReadConsoleOutput(CON.hdl, - CON.save_screen, - bufferSize, - bufferCoord, - &readRegion)) { - result = TRUE; - CON.window_only = TRUE; - } else { - T((" error %#lx", (unsigned long) GetLastError())); - } - } + return result; +} + +/* + * 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; + + 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 (read_screen_data()) { + result = TRUE; + } else { + + 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; + + CON.window_only = TRUE; + + if (read_screen_data()) { + result = TRUE; } } @@ -987,7 +1245,7 @@ wcon_init(TERMINAL_CONTROL_BLOCK * TCB) AssertTCB(); if (TCB) { - if (CON.hdl == INVALID_HANDLE_VALUE) { + if (!InitConsole()) { returnVoid; } @@ -1019,12 +1277,13 @@ wcon_initpair(TERMINAL_CONTROL_BLOCK * TCB, { SCREEN *sp; - AssertTCB(); - SetSP(); + if (okConsoleHandle(TCB)) { + SetSP(); - if ((pair > 0) && (pair < NUMPAIRS) && (f >= 0) && (f < 8) - && (b >= 0) && (b < 8)) { - CON.pairs[pair] = MapColor(true, f) | MapColor(false, b); + if ((pair > 0) && (pair < NUMPAIRS) && (f >= 0) && (f < 8) + && (b >= 0) && (b < 8)) { + CON.pairs[pair] = MapColor(true, f) | MapColor(false, b); + } } } @@ -1060,29 +1319,33 @@ wcon_initmouse(TERMINAL_CONTROL_BLOCK * TCB) { SCREEN *sp; - AssertTCB(); - SetSP(); + if (okConsoleHandle(TCB)) { + SetSP(); - sp->_mouse_type = M_TERM_DRIVER; + sp->_mouse_type = M_TERM_DRIVER; + } } static int -wcon_testmouse(TERMINAL_CONTROL_BLOCK * TCB, int delay) +wcon_testmouse(TERMINAL_CONTROL_BLOCK * TCB, + int delay + EVENTLIST_2nd(_nc_eventlist * evl)) { int rc = 0; SCREEN *sp; - AssertTCB(); - SetSP(); + if (okConsoleHandle(TCB)) { + SetSP(); - if (sp->_drv_mouse_head < sp->_drv_mouse_tail) { - rc = TW_MOUSE; - } else { - rc = TCBOf(sp)->drv->td_twait(TCBOf(sp), - TWAIT_MASK, - delay, - (int *) 0 - EVENTLIST_2nd(evl)); + if (sp->_drv_mouse_head < sp->_drv_mouse_tail) { + rc = TW_MOUSE; + } else { + rc = TCBOf(sp)->drv->td_twait(TCBOf(sp), + TWAIT_MASK, + delay, + (int *) 0 + EVENTLIST_2nd(evl)); + } } return rc; @@ -1179,13 +1442,14 @@ wcon_initacs(TERMINAL_CONTROL_BLOCK * TCB, unsigned n; SCREEN *sp; - AssertTCB(); - SetSP(); + if (okConsoleHandle(TCB)) { + SetSP(); - for (n = 0; n < SIZEOF(table); ++n) { - 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; + for (n = 0; n < SIZEOF(table); ++n) { + 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; + } } } @@ -1208,11 +1472,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; } @@ -1222,10 +1486,10 @@ Adjust(int milliseconds, int diff) FROM_LEFT_4TH_BUTTON_PRESSED | \ RIGHTMOST_BUTTON_PRESSED) -static int +static mmask_t decode_mouse(SCREEN *sp, int mask) { - int result = 0; + mmask_t result = 0; (void) sp; assert(sp && console_initialized); @@ -1277,6 +1541,10 @@ console_twait( int diff; bool isImmed = (milliseconds == 0); +#ifdef NCURSES_WGETCH_EVENTS + (void) evl; /* TODO: implement wgetch-events */ +#endif + #define CONSUME() ReadConsoleInput(fd,&inp_rec,1,&nRead) assert(sp); @@ -1296,7 +1564,7 @@ console_twait( diff = (int) tdiff(fstart, fend); milliseconds = Adjust(milliseconds, diff); - if (!isImmed && milliseconds == 0) + if (!isImmed && milliseconds <= 0) break; if (rc == WAIT_OBJECT_0) { @@ -1314,7 +1582,7 @@ console_twait( if (inp_rec.Event.KeyEvent.bKeyDown) { if (0 == ch) { int nKey = MapKey(vk); - if ((nKey < 0) || FALSE == sp->_keypad_on) { + if (nKey < 0) { CONSUME(); continue; } @@ -1336,7 +1604,9 @@ console_twait( goto end; } continue; + /* e.g., FOCUS_EVENT */ default: + CONSUME(); selectActiveHandle(); continue; } @@ -1373,16 +1643,17 @@ wcon_twait(TERMINAL_CONTROL_BLOCK * TCB, EVENTLIST_2nd(_nc_eventlist * evl)) { SCREEN *sp; - int code; + int code = 0; - AssertTCB(); - SetSP(); + if (okConsoleHandle(TCB)) { + SetSP(); - code = console_twait(sp, - CON.inp, - mode, - milliseconds, - timeleft EVENTLIST_2nd(_nc_eventlist * evl)); + code = console_twait(sp, + CON.inp, + mode, + milliseconds, + timeleft EVENTLIST_2nd(evl)); + } return code; } @@ -1407,14 +1678,14 @@ handle_mouse(SCREEN *sp, MOUSE_EVENT_RECORD mer) if (sp->_drv_mouse_new_buttons) { - work.bstate |= (mmask_t) decode_mouse(sp, sp->_drv_mouse_new_buttons); + work.bstate |= decode_mouse(sp, sp->_drv_mouse_new_buttons); } else { /* cf: BUTTON_PRESSED, BUTTON_RELEASED */ - work.bstate |= (mmask_t) (decode_mouse(sp, - sp->_drv_mouse_old_buttons) - >> 1); + work.bstate |= (decode_mouse(sp, + sp->_drv_mouse_old_buttons) + >> 1); result = TRUE; } @@ -1433,14 +1704,16 @@ static int wcon_read(TERMINAL_CONTROL_BLOCK * TCB, int *buf) { SCREEN *sp; - int n; + int n = -1; + + T((T_CALLED("win32con::wcon_read(%p)"), TCB)); - AssertTCB(); assert(buf); - SetSP(); + if (okConsoleHandle(TCB)) { + SetSP(); - T((T_CALLED("win32con::wcon_read(%p)"), TCB)); - n = _nc_mingw_console_read(sp, CON.inp, buf); + n = _nc_mingw_console_read(sp, CON.inp, buf); + } returnCode(n); } @@ -1452,6 +1725,29 @@ wcon_nap(TERMINAL_CONTROL_BLOCK * TCB GCC_UNUSED, int ms) returnCode(OK); } +static int +wcon_cursorSet(TERMINAL_CONTROL_BLOCK * TCB GCC_UNUSED, int mode) +{ + int res = -1; + + T((T_CALLED("win32con:wcon_cursorSet(%d)"), mode)); + if (okConsoleHandle(TCB)) { + CONSOLE_CURSOR_INFO this_CI = CON.save_CI; + 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 wcon_kyExist(TERMINAL_CONTROL_BLOCK * TCB GCC_UNUSED, int keycode) { @@ -1481,12 +1777,14 @@ wcon_kpad(TERMINAL_CONTROL_BLOCK * TCB, int flag GCC_UNUSED) SCREEN *sp; int code = ERR; - AssertTCB(); - SetSP(); - T((T_CALLED("win32con::wcon_kpad(%p, %d)"), TCB, flag)); - if (sp) { - code = OK; + + if (okConsoleHandle(TCB)) { + SetSP(); + + if (sp) { + code = OK; + } } returnCode(code); } @@ -1505,22 +1803,23 @@ wcon_keyok(TERMINAL_CONTROL_BLOCK * TCB, T((T_CALLED("win32con::wcon_keyok(%p, %d, %d)"), TCB, keycode, flag)); - AssertTCB(); - SetSP(); - - if (sp) { - res = bsearch(&key, - CON.rmap, - (size_t) (N_INI + FKEYS), - sizeof(keylist[0]), - rkeycompare); - if (res) { - key = *((LONG *) res); - vKey = HIWORD(key); - nKey = (LOWORD(key)) & 0x7fff; - if (!flag) - nKey |= 0x8000; - *(LONG *) res = GenMap(vKey, nKey); + if (okConsoleHandle(TCB)) { + SetSP(); + + if (sp) { + res = bsearch(&key, + CON.rmap, + (size_t) (N_INI + FKEYS), + sizeof(keylist[0]), + rkeycompare); + if (res) { + key = *((LONG *) res); + vKey = HIWORD(key); + nKey = (LOWORD(key)) & 0x7fff; + if (!flag) + nKey |= 0x8000; + *(LONG *) res = GenMap(vKey, nKey); + } } } returnCode(code); @@ -1562,7 +1861,8 @@ NCURSES_EXPORT_VAR (TERM_DRIVER) _nc_WIN_DRIVER = { wcon_nap, /* nap */ wcon_kpad, /* kpad */ wcon_keyok, /* kyOk */ - wcon_kyExist /* kyExist */ + wcon_kyExist, /* kyExist */ + wcon_cursorSet /* cursorSet */ }; /* --------------------------------------------------------- */ @@ -1577,7 +1877,7 @@ get_handle(int fd) #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 + application. mintty doesn't use Windows Console for its 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 @@ -1641,17 +1941,21 @@ _ismintty(int fd, LPHANDLE pMinTTY) #endif /* Borrowed from ansicon project. - Check wether or not a I/O handle is associated with + 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)) { - return (int) WriteConsoleA(hdl, NULL, 0, &dwFlag, NULL); + result = (int) WriteConsoleA(hdl, NULL, 0, &dwFlag, NULL); + } else { + result = (int) (dwFlag & ENABLE_PROCESSED_OUTPUT); } - return (int) (dwFlag & ENABLE_PROCESSED_OUTPUT); + return result; } /* Our replacement for the systems _isatty to include also @@ -1661,18 +1965,21 @@ IsConsoleHandle(HANDLE hdl) int _nc_mingw_isatty(int fd) { - if (_isatty(fd)) - return 1; -#if WINVER < 0x0600 - return 0; -#else - return _ismintty(fd, NULL); + int result = 0; + + 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 + Console. It is the responsibility of the console to deal with the terminal escape sequences that are sent by terminfo. */ @@ -1693,15 +2000,15 @@ _nc_mingw_isconsole(int fd) SCREEN *sp; \ TERMINAL *term = 0; \ int code = ERR; \ - if (_nc_screen_chain==0) \ - return 0; \ + if (_nc_screen_chain == 0) \ + return 0; \ for (each_screen(sp)) { \ - if (sp->_term && sp->_term->Filedes==fd) { \ - term = sp->_term; \ - break; \ + if (sp->_term && (sp->_term->Filedes == fd)) { \ + term = sp->_term; \ + break; \ } \ } \ - assert(term!=0) + assert(term != 0) int _nc_mingw_tcsetattr( @@ -1774,7 +2081,8 @@ int _nc_mingw_testmouse( SCREEN *sp, HANDLE fd, - int delay) + int delay + EVENTLIST_2nd(_nc_eventlist * evl)) { int rc = 0; @@ -1799,7 +2107,7 @@ _nc_mingw_console_read( HANDLE fd, int *buf) { - int n = 1; + int rc = -1; INPUT_RECORD inp_rec; BOOL b; DWORD nRead; @@ -1814,23 +2122,41 @@ _nc_mingw_console_read( while ((b = ReadConsoleInput(fd, &inp_rec, 1, &nRead))) { if (b && nRead > 0) { + if (rc < 0) + rc = 0; + rc = rc + (int) nRead; 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 (defined in winuser.h), + * and typically 12 function-keys on a keyboard. Use the + * shift-modifier to provide the remaining keys. + */ + if (vk >= VK_F1 && vk <= VK_F12) { + if (inp_rec.Event.KeyEvent.dwControlKeyState & SHIFT_PRESSED) { + vk = (WORD) (vk + 12); + } + } if (*buf == 0) { - if (sp->_keypad_on) { - *buf = MapKey(vk); - if (0 > (*buf)) - continue; - else - break; - } else + int key = MapKey(vk); + if (key < 0) continue; - } else { /* *buf != 0 */ - break; + if (sp->_keypad_on) { + *buf = key; + } else { + ungetch('\0'); + *buf = AnsiKey(vk); + } + } else if (vk == VK_BACK) { + if (!(inp_rec.Event.KeyEvent.dwControlKeyState + & (SHIFT_PRESSED | CONTROL_PRESSED))) { + *buf = KEY_BACKSPACE; + } } + break; } else if (inp_rec.EventType == MOUSE_EVENT) { if (handle_mouse(sp, inp_rec.Event.MouseEvent)) { @@ -1841,13 +2167,13 @@ _nc_mingw_console_read( continue; } } - returnCode(n); + returnCode(rc); } -static -__attribute__((constructor)) - void _enter_console(void) +static bool +InitConsole(void) { + /* initialize once, or not at all */ if (!console_initialized) { int i; DWORD num_buttons; @@ -1855,19 +2181,26 @@ __attribute__((constructor)) BOOL buffered = TRUE; BOOL b; - if (_nc_mingw_isatty(0)) { - CON.isMinTTY = TRUE; - } + START_TRACE(); for (i = 0; i < (N_INI + FKEYS); i++) { - if (i < N_INI) + if (i < N_INI) { CON.rmap[i] = CON.map[i] = (DWORD) keylist[i]; - else + 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]), @@ -1887,20 +2220,22 @@ __attribute__((constructor)) 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); + CON.inp = GetDirectHandle("CONIN$", FILE_SHARE_READ); + CON.out = GetDirectHandle("CONOUT$", FILE_SHARE_WRITE); + if (getenv("NCGDB") || getenv("NCURSES_CONSOLE2")) { - CON.hdl = CON.out; + T(("... will not buffer console")); buffered = FALSE; + CON.hdl = CON.out; } else { + T(("... creating console buffer")); CON.hdl = CreateConsoleScreenBuffer(GENERIC_READ | GENERIC_WRITE, - 0, + FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, CONSOLE_TEXTMODE_BUFFER, NULL); @@ -1909,11 +2244,39 @@ __attribute__((constructor)) 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; } + return (CON.hdl != INVALID_HANDLE_VALUE); } + +static bool +okConsoleHandle(TERMINAL_CONTROL_BLOCK * TCB) +{ + return ((TCB != 0) && + (TCB->magic == WINMAGIC) && + InitConsole()); +} + +/* + * While a constructor would ensure that this module is initialized, that will + * interfere with applications that may combine this with GUI interfaces. + */ +#if 0 +static +__attribute__((constructor)) + void _enter_console(void) +{ + (void) InitConsole(); +} +#endif