Set margins per console; fix windowless processes

I had intended for margins to be set per process, but during testing I
was wondering why they weren't working, so per console it is.

In changing the above, I realised that `pState` may stay `NULL` when a
process is created without a window.  Initialise it to a default state,
updating it when the window becomes available.
This commit is contained in:
Jason Hood 2017-12-23 18:31:37 +10:00
parent a37657ac52
commit 4502a49bab
2 changed files with 72 additions and 66 deletions

137
ANSI.c
View File

@ -177,7 +177,8 @@
BS/CUB/HPB after wrap will move back to the previous line(s); BS/CUB/HPB after wrap will move back to the previous line(s);
added DECOM, DECSTBM, SD & SU; added DECOM, DECSTBM, SD & SU;
only flush before accessing the console, adding a mode to flush immediately; only flush before accessing the console, adding a mode to flush immediately;
added DECSTR & RIS. added DECSTR & RIS;
fix state problems with windowless processes.
*/ */
#include "ansicon.h" #include "ansicon.h"
@ -225,8 +226,7 @@ TCHAR Pt_arg[MAX_PATH*2]; // text parameter for Operating System Command
int Pt_len; int Pt_len;
BOOL shifted, G0_special, SaveG0; BOOL shifted, G0_special, SaveG0;
BOOL awm = TRUE; // autowrap mode BOOL awm = TRUE; // autowrap mode
BOOL im, om, tb_margins; // insert mode, origin mode, top/bottom margins BOOL im; // insert mode
int top_margin, bot_margin;
int screen_top = -1; // initial window top when cleared int screen_top = -1; // initial window top when cleared
@ -414,6 +414,10 @@ typedef struct
WORD SaveAttr; WORD SaveAttr;
BYTE fm; // flush mode BYTE fm; // flush mode
BYTE crm; // showing control characters? BYTE crm; // showing control characters?
BYTE om; // origin mode
BYTE tb_margins; // top/bottom margins set?
SHORT top_margin;
SHORT bot_margin;
COORD SavePos; // saved cursor position COORD SavePos; // saved cursor position
COLORREF palette[16]; COLORREF palette[16];
SHORT buf_width; // buffer width prior to setting 132 columns SHORT buf_width; // buffer width prior to setting 132 columns
@ -423,7 +427,9 @@ typedef struct
BYTE tab_stop[MAX_TABS]; BYTE tab_stop[MAX_TABS];
} STATE, *PSTATE; } STATE, *PSTATE;
PSTATE pState; STATE default_state; // for when there's no window or file mapping
PSTATE pState = &default_state;
BOOL valid_state;
HANDLE hMap; HANDLE hMap;
void set_ansicon( PCONSOLE_SCREEN_BUFFER_INFO ); void set_ansicon( PCONSOLE_SCREEN_BUFFER_INFO );
@ -437,39 +443,32 @@ void get_state( void )
HANDLE hConOut; HANDLE hConOut;
CONSOLE_SCREEN_BUFFER_INFO Info; CONSOLE_SCREEN_BUFFER_INFO Info;
CONSOLE_SCREEN_BUFFER_INFOX csbix; CONSOLE_SCREEN_BUFFER_INFOX csbix;
static STATE state; // on the odd chance file mapping fails
if (pState != NULL) if (valid_state)
return; return;
hwnd = GetConsoleWindow(); hwnd = GetConsoleWindow();
if (hwnd == NULL) if (hwnd == NULL)
return; return;
valid_state = TRUE;
wsprintf( buf, L"ANSICON_State_%X", PtrToUint( hwnd ) ); wsprintf( buf, L"ANSICON_State_%X", PtrToUint( hwnd ) );
hMap = CreateFileMapping( INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, hMap = CreateFileMapping( INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE,
0, sizeof(STATE), buf ); 0, sizeof(STATE), buf );
if (hMap == NULL)
{
no_go:
DEBUGSTR( 1, "File mapping failed (%u) - using default state",
GetLastError() );
pState = &state;
goto do_init;
}
init = (GetLastError() != ERROR_ALREADY_EXISTS); init = (GetLastError() != ERROR_ALREADY_EXISTS);
pState = MapViewOfFile( hMap, FILE_MAP_ALL_ACCESS, 0, 0, 0 ); pState = MapViewOfFile( hMap, FILE_MAP_ALL_ACCESS, 0, 0, 0 );
if (pState == NULL) if (pState == NULL)
{ {
DEBUGSTR( 1, "File mapping failed (%u) - using default state",
GetLastError() );
pState = &default_state;
CloseHandle( hMap ); CloseHandle( hMap );
hMap = NULL; hMap = NULL;
goto no_go;
} }
if (init) if (init)
{ {
do_init:
hConOut = CreateFile( L"CONOUT$", GENERIC_READ | GENERIC_WRITE, hConOut = CreateFile( L"CONOUT$", GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL, OPEN_EXISTING, 0, NULL ); NULL, OPEN_EXISTING, 0, NULL );
@ -625,7 +624,7 @@ void FlushBuffer( void )
CONSOLE_CURSOR_INFO cci; CONSOLE_CURSOR_INFO cci;
CONSOLE_SCREEN_BUFFER_INFO Info, wi; CONSOLE_SCREEN_BUFFER_INFO Info, wi;
if (nCharInBuffer < 4 && !im && !tb_margins) if (nCharInBuffer < 4 && !im && !pState->tb_margins)
{ {
LPWSTR b = ChBuffer; LPWSTR b = ChBuffer;
do do
@ -670,9 +669,9 @@ void FlushBuffer( void )
SetConsoleMode( hConWrap, ENABLE_PROCESSED_OUTPUT ); SetConsoleMode( hConWrap, ENABLE_PROCESSED_OUTPUT );
WriteConsole( hConWrap, ChBuffer, nCharInBuffer, &nWritten, NULL ); WriteConsole( hConWrap, ChBuffer, nCharInBuffer, &nWritten, NULL );
GetConsoleScreenBufferInfo( hConWrap, &wi ); GetConsoleScreenBufferInfo( hConWrap, &wi );
if (tb_margins && CUR.Y + wi.CURPOS.Y > TOP + bot_margin) if (pState->tb_margins && CUR.Y + wi.CURPOS.Y > TOP + pState->bot_margin)
{ {
if (CUR.Y > TOP + bot_margin) if (CUR.Y > TOP + pState->bot_margin)
{ {
// If we're at the bottom of the window, outside the margins, then // If we're at the bottom of the window, outside the margins, then
// just keep overwriting the last line. // just keep overwriting the last line.
@ -717,29 +716,30 @@ void FlushBuffer( void )
} }
} }
} }
else if (wi.CURPOS.Y > bot_margin - top_margin) else if (wi.CURPOS.Y > pState->bot_margin - pState->top_margin)
{ {
// The line is bigger than the scroll region, copy that portion. // The line is bigger than the scroll region, copy that portion.
PCHAR_INFO row = HeapAlloc( hHeap, 0, (bot_margin - top_margin + 1) PCHAR_INFO row = HeapAlloc( hHeap, 0,
* WIDTH * sizeof(CHAR_INFO) ); (pState->bot_margin - pState->top_margin + 1)
* WIDTH * sizeof(CHAR_INFO) );
if (row != NULL) if (row != NULL)
{ {
COORD s, c; COORD s, c;
SMALL_RECT r; SMALL_RECT r;
s.X = WIDTH; s.X = WIDTH;
s.Y = bot_margin - top_margin + 1; s.Y = pState->bot_margin - pState->top_margin + 1;
c.X = c.Y = 0; c.X = c.Y = 0;
r.Left = LEFT; r.Left = LEFT;
r.Right = RIGHT; r.Right = RIGHT;
r.Bottom = wi.CURPOS.Y; r.Bottom = wi.CURPOS.Y;
r.Top = r.Bottom - (bot_margin - top_margin); r.Top = r.Bottom - (pState->bot_margin - pState->top_margin);
ReadConsoleOutput( hConWrap, row, s, c, &r ); ReadConsoleOutput( hConWrap, row, s, c, &r );
r.Top = TOP + top_margin; r.Top = TOP + pState->top_margin;
r.Bottom = TOP + bot_margin; r.Bottom = TOP + pState->bot_margin;
WriteConsoleOutput( hConOut, row, s, c, &r ); WriteConsoleOutput( hConOut, row, s, c, &r );
HeapFree( hHeap, 0, row ); HeapFree( hHeap, 0, row );
CloseHandle( hConWrap ); CloseHandle( hConWrap );
nWrapped = bot_margin - top_margin; nWrapped = pState->bot_margin - pState->top_margin;
nCharInBuffer = 0; nCharInBuffer = 0;
return; return;
} }
@ -756,8 +756,8 @@ void FlushBuffer( void )
c.X = c.X =
sr.Left = LEFT; sr.Left = LEFT;
sr.Right = RIGHT; sr.Right = RIGHT;
sr.Top = TOP + top_margin; sr.Top = TOP + pState->top_margin;
sr.Bottom = TOP + bot_margin; sr.Bottom = TOP + pState->bot_margin;
c.Y = sr.Top - wi.CURPOS.Y; c.Y = sr.Top - wi.CURPOS.Y;
ScrollConsoleScreenBuffer( hConOut, &sr, &sr, c, &ci ); ScrollConsoleScreenBuffer( hConOut, &sr, &sr, c, &ci );
CUR.Y -= wi.CURPOS.Y; CUR.Y -= wi.CURPOS.Y;
@ -960,9 +960,9 @@ void Reset( BOOL hard )
CursInfo.bVisible = TRUE; CursInfo.bVisible = TRUE;
SetConsoleCursorInfo( hConOut, &CursInfo ); SetConsoleCursorInfo( hConOut, &CursInfo );
im = im =
om = pState->om =
tb_margins = pState->crm =
pState->crm = FALSE; pState->tb_margins = FALSE;
awm = TRUE; awm = TRUE;
SetConsoleMode( hConOut, cache[0].mode | ENABLE_WRAP_AT_EOL_OUTPUT ); SetConsoleMode( hConOut, cache[0].mode | ENABLE_WRAP_AT_EOL_OUTPUT );
shifted = G0_special = SaveG0 = FALSE; shifted = G0_special = SaveG0 = FALSE;
@ -1057,7 +1057,7 @@ void InterpretEscSeq( void )
break; break;
case 6: // DECOM case 6: // DECOM
om = (suffix == 'h'); pState->om = (suffix == 'h');
break; break;
case 95: // DECNCSM case 95: // DECNCSM
@ -1069,7 +1069,7 @@ void InterpretEscSeq( void )
COORD buf; COORD buf;
SMALL_RECT win; SMALL_RECT win;
tb_margins = FALSE; pState->tb_margins = FALSE;
buf.X = (suffix == 'l') ? pState->buf_width : 132; buf.X = (suffix == 'l') ? pState->buf_width : 132;
if (buf.X != 0) if (buf.X != 0)
@ -1371,17 +1371,19 @@ void InterpretEscSeq( void )
case 'r': // DECSTBM - ESC[#;#r Set top and bottom margins. case 'r': // DECSTBM - ESC[#;#r Set top and bottom margins.
if (es_argc == 0 && suffix2 == '+') if (es_argc == 0 && suffix2 == '+')
{ {
tb_margins = FALSE; // ESC[+r == remove margins pState->tb_margins = FALSE; // ESC[+r == remove margins
return; return;
} }
if (es_argc > 2) return; if (es_argc > 2) return;
if (es_argv[1] == 0) es_argv[1] = BOTTOM - TOP + 1; if (es_argv[1] == 0) es_argv[1] = BOTTOM - TOP + 1;
top_margin = p1 - 1; pState->top_margin = p1 - 1;
bot_margin = es_argv[1] - 1; pState->bot_margin = es_argv[1] - 1;
if (bot_margin > BOTTOM - TOP) bot_margin = BOTTOM - TOP; if (pState->bot_margin > BOTTOM - TOP)
if (top_margin >= bot_margin) return; // top must be less than bottom pState->bot_margin = BOTTOM - TOP;
tb_margins = TRUE; if (pState->top_margin >= pState->bot_margin)
set_pos( LEFT, om ? TOP + top_margin : TOP ); return; // top must be less than bottom
pState->tb_margins = TRUE;
set_pos( LEFT, pState->om ? TOP + pState->top_margin : TOP );
return; return;
case 'S': // SU - ESC[#S Scroll up/Pan down. case 'S': // SU - ESC[#S Scroll up/Pan down.
@ -1390,10 +1392,10 @@ void InterpretEscSeq( void )
Pos.X = Pos.X =
Rect.Left = LEFT; Rect.Left = LEFT;
Rect.Right = RIGHT; Rect.Right = RIGHT;
if (tb_margins) if (pState->tb_margins)
{ {
Rect.Top = TOP + top_margin; Rect.Top = TOP + pState->top_margin;
Rect.Bottom = TOP + bot_margin; Rect.Bottom = TOP + pState->bot_margin;
} }
else else
{ {
@ -1413,10 +1415,11 @@ void InterpretEscSeq( void )
Rect.Left = LEFT; Rect.Left = LEFT;
Rect.Right = RIGHT; Rect.Right = RIGHT;
Rect.Top = CUR.Y; Rect.Top = CUR.Y;
if (tb_margins) if (pState->tb_margins)
{ {
if (CUR.Y < TOP + top_margin || CUR.Y > TOP + bot_margin) return; if (CUR.Y < TOP + pState->top_margin ||
Rect.Bottom = TOP + bot_margin; CUR.Y > TOP + pState->bot_margin) return;
Rect.Bottom = TOP + pState->bot_margin;
} }
else else
{ {
@ -1450,8 +1453,9 @@ void InterpretEscSeq( void )
case 'F': // CPL - ESC[#F Moves cursor up # lines, column 1. case 'F': // CPL - ESC[#F Moves cursor up # lines, column 1.
if (es_argc > 1) return; // ESC[A == ESC[1A if (es_argc > 1) return; // ESC[A == ESC[1A
Pos.Y = CUR.Y - p1; Pos.Y = CUR.Y - p1;
if (tb_margins && (om || CUR.Y >= TOP + top_margin)) if (pState->tb_margins && (pState->om ||
top = TOP + top_margin; CUR.Y >= TOP + pState->top_margin))
top = TOP + pState->top_margin;
if (Pos.Y < top) Pos.Y = top; if (Pos.Y < top) Pos.Y = top;
set_pos( (suffix == 'F') ? LEFT : CUR.X, Pos.Y ); set_pos( (suffix == 'F') ? LEFT : CUR.X, Pos.Y );
return; return;
@ -1461,8 +1465,9 @@ void InterpretEscSeq( void )
case 'E': // CNL - ESC[#E Moves cursor down # lines, column 1. case 'E': // CNL - ESC[#E Moves cursor down # lines, column 1.
if (es_argc > 1) return; // ESC[B == ESC[1B if (es_argc > 1) return; // ESC[B == ESC[1B
Pos.Y = CUR.Y + p1; Pos.Y = CUR.Y + p1;
if (tb_margins && (om || CUR.Y <= TOP + bot_margin)) if (pState->tb_margins && (pState->om ||
bottom = TOP + bot_margin; CUR.Y <= TOP + pState->bot_margin))
bottom = TOP + pState->bot_margin;
if (Pos.Y > bottom) Pos.Y = bottom; if (Pos.Y > bottom) Pos.Y = bottom;
set_pos( (suffix == 'E') ? LEFT : CUR.X, Pos.Y ); set_pos( (suffix == 'E') ? LEFT : CUR.X, Pos.Y );
return; return;
@ -1506,10 +1511,10 @@ void InterpretEscSeq( void )
case 'd': // VPA - ESC[#d Moves cursor row #, current column. case 'd': // VPA - ESC[#d Moves cursor row #, current column.
if (es_argc > 1) return; // ESC[d == ESC[1d if (es_argc > 1) return; // ESC[d == ESC[1d
if (tb_margins && om) if (pState->tb_margins && pState->om)
{ {
top = TOP + top_margin; top = TOP + pState->top_margin;
bottom = TOP + bot_margin; bottom = TOP + pState->bot_margin;
} }
Pos.Y = top + p1 - 1; Pos.Y = top + p1 - 1;
if (Pos.Y < top) Pos.Y = top; if (Pos.Y < top) Pos.Y = top;
@ -1893,14 +1898,14 @@ void MoveDown( BOOL home )
CHAR_INFO CharInfo; CHAR_INFO CharInfo;
GetConsoleScreenBufferInfo( hConOut, &Info ); GetConsoleScreenBufferInfo( hConOut, &Info );
if (tb_margins && CUR.Y == TOP + bot_margin) if (pState->tb_margins && CUR.Y == TOP + pState->bot_margin)
{ {
Rect.Left = LEFT; Rect.Left = LEFT;
Rect.Right = RIGHT; Rect.Right = RIGHT;
Rect.Top = TOP + top_margin + 1; Rect.Top = TOP + pState->top_margin + 1;
Rect.Bottom = TOP + bot_margin; Rect.Bottom = TOP + pState->bot_margin;
Pos.X = LEFT; Pos.X = LEFT;
Pos.Y = TOP + top_margin; Pos.Y = TOP + pState->top_margin;
CharInfo.Char.UnicodeChar = ' '; CharInfo.Char.UnicodeChar = ' ';
CharInfo.Attributes = ATTR; CharInfo.Attributes = ATTR;
ScrollConsoleScreenBuffer( hConOut, &Rect, NULL, Pos, &CharInfo ); ScrollConsoleScreenBuffer( hConOut, &Rect, NULL, Pos, &CharInfo );
@ -1910,7 +1915,7 @@ void MoveDown( BOOL home )
SetConsoleCursorPosition( hConOut, CUR ); SetConsoleCursorPosition( hConOut, CUR );
} }
} }
else if (tb_margins && CUR.Y == BOTTOM) else if (pState->tb_margins && CUR.Y == BOTTOM)
{ {
if (home) if (home)
{ {
@ -1950,19 +1955,19 @@ void MoveUp( void )
CHAR_INFO CharInfo; CHAR_INFO CharInfo;
GetConsoleScreenBufferInfo( hConOut, &Info ); GetConsoleScreenBufferInfo( hConOut, &Info );
if (tb_margins && CUR.Y == TOP + top_margin) if (pState->tb_margins && CUR.Y == TOP + pState->top_margin)
{ {
Rect.Left = LEFT; Rect.Left = LEFT;
Rect.Right = RIGHT; Rect.Right = RIGHT;
Rect.Top = TOP + top_margin; Rect.Top = TOP + pState->top_margin;
Rect.Bottom = TOP + bot_margin - 1; Rect.Bottom = TOP + pState->bot_margin - 1;
Pos.X = LEFT; Pos.X = LEFT;
Pos.Y = TOP + top_margin + 1; Pos.Y = TOP + pState->top_margin + 1;
CharInfo.Char.UnicodeChar = ' '; CharInfo.Char.UnicodeChar = ' ';
CharInfo.Attributes = ATTR; CharInfo.Attributes = ATTR;
ScrollConsoleScreenBuffer( hConOut, &Rect, NULL, Pos, &CharInfo ); ScrollConsoleScreenBuffer( hConOut, &Rect, NULL, Pos, &CharInfo );
} }
else if (tb_margins && CUR.Y == TOP) else if (pState->tb_margins && CUR.Y == TOP)
{ {
// do nothing // do nothing
} }
@ -2044,7 +2049,7 @@ ParseAndPrintString( HANDLE hDev,
} }
else if (c == SO) shifted = TRUE; else if (c == SO) shifted = TRUE;
else if (c == SI) shifted = G0_special; else if (c == SI) shifted = G0_special;
else if (c == HT && pState != NULL && pState->tabs) else if (c == HT && pState->tabs)
{ {
CONSOLE_SCREEN_BUFFER_INFO Info; CONSOLE_SCREEN_BUFFER_INFO Info;
FlushBuffer(); FlushBuffer();

View File

@ -333,6 +333,7 @@ Version History
- fix issues with CRM; - fix issues with CRM;
- fix explicit zero parameters not defaulting to 1; - fix explicit zero parameters not defaulting to 1;
- set color by index (also setting bold/underline); - set color by index (also setting bold/underline);
- fix processes that start without a window;
* limit parameters to a maximum value of 32767; * limit parameters to a maximum value of 32767;
* go back to saving the buffer cursor position; * go back to saving the buffer cursor position;
* preserve escape that isn't part of a sequence; * preserve escape that isn't part of a sequence;