Add DECOM, DECSTBM, SD and SU
Margins always use the window, never the buffer; the exception is `\e[+r` which will remove the margins ('\e[r' will set the margins to the window). With the margins set, the window will not scroll when the cursor is at the bottom, outside of the margins. In this case, the display is not quite right, since I copy the line from another buffer, rather than actually overwrite the existing line.
This commit is contained in:
parent
9242785570
commit
77fabb78e0
521
ANSI.c
521
ANSI.c
@ -152,7 +152,7 @@
|
||||
remove wcstok, avoiding potential interference with the host;
|
||||
similarly, use a private heap instead of malloc.
|
||||
|
||||
v1.80, 26 October to 19 December, 2017:
|
||||
v1.80, 26 October to 21 December, 2017:
|
||||
fix unloading;
|
||||
revert back to (re)storing buffer cursor position;
|
||||
increase cache to five handles;
|
||||
@ -174,7 +174,8 @@
|
||||
added tab handling;
|
||||
added the bright SGR colors, recognised the system indices;
|
||||
added insert mode;
|
||||
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.
|
||||
*/
|
||||
|
||||
#include "ansicon.h"
|
||||
@ -220,7 +221,9 @@ int es_argv[MAX_ARG]; // escape sequence args
|
||||
TCHAR Pt_arg[MAX_PATH*2]; // text parameter for Operating System Command
|
||||
int Pt_len;
|
||||
BOOL shifted, G0_special, SaveG0;
|
||||
BOOL im; // insert mode?
|
||||
BOOL awm = TRUE; // autowrap mode
|
||||
BOOL im, om, tb_margins; // insert mode, origin mode, top/bottom margins
|
||||
int top_margin, bot_margin;
|
||||
int screen_top = -1; // initial window top when cleared
|
||||
|
||||
|
||||
@ -357,6 +360,20 @@ typedef BOOL (WINAPI *PHCSBIX)(
|
||||
PHCSBIX GetConsoleScreenBufferInfoX, SetConsoleScreenBufferInfoX;
|
||||
|
||||
|
||||
// Reduce verbosity.
|
||||
#define CURPOS dwCursorPosition
|
||||
#define ATTR Info.wAttributes
|
||||
#define WIDTH Info.dwSize.X
|
||||
#define HEIGHT Info.dwSize.Y
|
||||
#define CUR Info.CURPOS
|
||||
#define WIN Info.srWindow
|
||||
#define TOP WIN.Top
|
||||
#define BOTTOM WIN.Bottom
|
||||
#define LAST (HEIGHT - 1)
|
||||
#define LEFT 0
|
||||
#define RIGHT (WIDTH - 1)
|
||||
|
||||
|
||||
#define MAX_TABS 2048
|
||||
|
||||
typedef struct
|
||||
@ -396,7 +413,7 @@ void get_state( void )
|
||||
HWND hwnd;
|
||||
BOOL init;
|
||||
HANDLE hConOut;
|
||||
CONSOLE_SCREEN_BUFFER_INFO csbi;
|
||||
CONSOLE_SCREEN_BUFFER_INFO Info;
|
||||
CONSOLE_SCREEN_BUFFER_INFOX csbix;
|
||||
static STATE state; // on the odd chance file mapping fails
|
||||
|
||||
@ -438,38 +455,38 @@ void get_state( void )
|
||||
if (GetConsoleScreenBufferInfoX &&
|
||||
GetConsoleScreenBufferInfoX( hConOut, &csbix ))
|
||||
{
|
||||
csbi.dwSize = csbix.dwSize;
|
||||
csbi.wAttributes = csbix.wAttributes;
|
||||
csbi.srWindow = csbix.srWindow;
|
||||
Info.dwSize = csbix.dwSize;
|
||||
ATTR = csbix.wAttributes;
|
||||
WIN = csbix.srWindow;
|
||||
memcpy( pState->palette, csbix.ColorTable, sizeof(csbix.ColorTable) );
|
||||
}
|
||||
else if (!GetConsoleScreenBufferInfo( hConOut, &csbi ))
|
||||
else if (!GetConsoleScreenBufferInfo( hConOut, &Info ))
|
||||
{
|
||||
DEBUGSTR( 1, "Failed to get screen buffer info (%u) - assuming defaults",
|
||||
GetLastError() );
|
||||
csbi.wAttributes = 7;
|
||||
csbi.dwSize.X = 80;
|
||||
csbi.dwSize.Y = 300;
|
||||
csbi.srWindow.Left = 0;
|
||||
csbi.srWindow.Right = 79;
|
||||
csbi.srWindow.Top = 0;
|
||||
csbi.srWindow.Bottom = 24;
|
||||
ATTR = 7;
|
||||
WIDTH = 80;
|
||||
HEIGHT = 300;
|
||||
WIN.Left = 0;
|
||||
WIN.Right = 79;
|
||||
TOP = 0;
|
||||
BOTTOM = 24;
|
||||
}
|
||||
if (GetEnvironmentVariable( L"ANSICON_REVERSE", NULL, 0 ))
|
||||
{
|
||||
SetEnvironmentVariable( L"ANSICON_REVERSE", NULL );
|
||||
pState->sgr.reverse = TRUE;
|
||||
pState->sgr.foreground = attr2ansi[(csbi.wAttributes >> 4) & 7];
|
||||
pState->sgr.background = attr2ansi[csbi.wAttributes & 7];
|
||||
pState->sgr.bold = (csbi.wAttributes & BACKGROUND_INTENSITY) >> 4;
|
||||
pState->sgr.underline = (csbi.wAttributes & FOREGROUND_INTENSITY) << 4;
|
||||
pState->sgr.foreground = attr2ansi[(ATTR >> 4) & 7];
|
||||
pState->sgr.background = attr2ansi[ATTR & 7];
|
||||
pState->sgr.bold = (ATTR & BACKGROUND_INTENSITY) >> 4;
|
||||
pState->sgr.underline = (ATTR & FOREGROUND_INTENSITY) << 4;
|
||||
}
|
||||
else
|
||||
{
|
||||
pState->sgr.foreground = attr2ansi[csbi.wAttributes & 7];
|
||||
pState->sgr.background = attr2ansi[(csbi.wAttributes >> 4) & 7];
|
||||
pState->sgr.bold = csbi.wAttributes & FOREGROUND_INTENSITY;
|
||||
pState->sgr.underline = csbi.wAttributes & BACKGROUND_INTENSITY;
|
||||
pState->sgr.foreground = attr2ansi[ATTR & 7];
|
||||
pState->sgr.background = attr2ansi[(ATTR >> 4) & 7];
|
||||
pState->sgr.bold = ATTR & FOREGROUND_INTENSITY;
|
||||
pState->sgr.underline = ATTR & BACKGROUND_INTENSITY;
|
||||
}
|
||||
if (!GetEnvironmentVariable( L"ANSICON_DEF", NULL, 0 ))
|
||||
{
|
||||
@ -478,13 +495,12 @@ void get_state( void )
|
||||
if (pState->sgr.reverse)
|
||||
{
|
||||
*a++ = '-';
|
||||
csbi.wAttributes = ((csbi.wAttributes >> 4) & 15)
|
||||
| ((csbi.wAttributes & 15) << 4);
|
||||
ATTR = ((ATTR >> 4) & 15) | ((ATTR & 15) << 4);
|
||||
}
|
||||
wsprintf( a, L"%X", csbi.wAttributes & 255 );
|
||||
wsprintf( a, L"%X", ATTR & 255 );
|
||||
SetEnvironmentVariable( L"ANSICON_DEF", def );
|
||||
}
|
||||
set_ansicon( &csbi );
|
||||
set_ansicon( &Info );
|
||||
CloseHandle( hConOut );
|
||||
}
|
||||
}
|
||||
@ -547,6 +563,8 @@ WCHAR ChBuffer[BUFFER_SIZE];
|
||||
WCHAR ChPrev;
|
||||
int nWrapped;
|
||||
|
||||
void MoveDown( BOOL home );
|
||||
|
||||
|
||||
// Set the cursor position, resetting the wrap flag.
|
||||
void set_pos( int x, int y )
|
||||
@ -568,20 +586,24 @@ void FlushBuffer( void )
|
||||
|
||||
if (nCharInBuffer <= 0) return;
|
||||
|
||||
if (pState->crm && !im)
|
||||
if (!awm && !im)
|
||||
{
|
||||
if (pState->crm)
|
||||
{
|
||||
SetConsoleMode( hConOut, cache[0].mode & ~ENABLE_PROCESSED_OUTPUT );
|
||||
WriteConsole( hConOut, ChBuffer, nCharInBuffer, &nWritten, NULL );
|
||||
SetConsoleMode( hConOut, cache[0].mode );
|
||||
}
|
||||
else
|
||||
WriteConsole( hConOut, ChBuffer, nCharInBuffer, &nWritten, NULL );
|
||||
}
|
||||
else
|
||||
{
|
||||
HANDLE hConWrap;
|
||||
CONSOLE_CURSOR_INFO cci;
|
||||
CONSOLE_SCREEN_BUFFER_INFO csbi;
|
||||
COORD here;
|
||||
CONSOLE_SCREEN_BUFFER_INFO Info, wi;
|
||||
|
||||
if (nCharInBuffer < 4 && !im)
|
||||
if (nCharInBuffer < 4 && !im && !tb_margins)
|
||||
{
|
||||
LPWSTR b = ChBuffer;
|
||||
do
|
||||
@ -589,8 +611,8 @@ void FlushBuffer( void )
|
||||
WriteConsole( hConOut, b, 1, &nWritten, NULL );
|
||||
if (*b != '\r' && *b != '\b' && *b != '\a')
|
||||
{
|
||||
GetConsoleScreenBufferInfo( hConOut, &csbi );
|
||||
if (csbi.dwCursorPosition.X == 0)
|
||||
GetConsoleScreenBufferInfo( hConOut, &Info );
|
||||
if (CUR.X == 0)
|
||||
++nWrapped;
|
||||
}
|
||||
} while (++b, --nCharInBuffer);
|
||||
@ -608,31 +630,130 @@ void FlushBuffer( void )
|
||||
cci.bVisible = FALSE;
|
||||
SetConsoleCursorInfo( hConWrap, &cci );
|
||||
// Ensure the buffer is the same width (it gets created using the window
|
||||
// width) and more than one line.
|
||||
GetConsoleScreenBufferInfo( hConOut, &csbi );
|
||||
here = csbi.dwCursorPosition;
|
||||
csbi.dwSize.Y = csbi.srWindow.Bottom - csbi.srWindow.Top + 2;
|
||||
SetConsoleScreenBufferSize( hConWrap, csbi.dwSize );
|
||||
// width) and contains sufficient lines.
|
||||
GetConsoleScreenBufferInfo( hConOut, &Info );
|
||||
if (WIN.Right - WIN.Left + 1 != WIDTH ||
|
||||
BOTTOM - TOP < 2 * nCharInBuffer % WIDTH)
|
||||
{
|
||||
HEIGHT = 2 * nCharInBuffer % WIDTH + 1;
|
||||
SetConsoleScreenBufferSize( hConWrap, Info.dwSize );
|
||||
}
|
||||
// Put the cursor on the top line, in the same column.
|
||||
csbi.dwCursorPosition.Y = 0;
|
||||
SetConsoleCursorPosition( hConWrap, csbi.dwCursorPosition );
|
||||
wi.CURPOS.X = CUR.X;
|
||||
wi.CURPOS.Y = 0;
|
||||
SetConsoleCursorPosition( hConWrap, wi.CURPOS );
|
||||
if (pState->crm)
|
||||
SetConsoleMode( hConWrap, ENABLE_WRAP_AT_EOL_OUTPUT );
|
||||
SetConsoleMode( hConWrap, (awm) ? ENABLE_WRAP_AT_EOL_OUTPUT : 0 );
|
||||
else if (!awm)
|
||||
SetConsoleMode( hConWrap, ENABLE_PROCESSED_OUTPUT );
|
||||
WriteConsole( hConWrap, ChBuffer, nCharInBuffer, &nWritten, NULL );
|
||||
GetConsoleScreenBufferInfo( hConWrap, &csbi );
|
||||
nWrapped += csbi.dwCursorPosition.Y;
|
||||
GetConsoleScreenBufferInfo( hConWrap, &wi );
|
||||
if (tb_margins && CUR.Y + wi.CURPOS.Y > TOP + bot_margin)
|
||||
{
|
||||
if (CUR.Y > TOP + bot_margin)
|
||||
{
|
||||
// If we're at the bottom of the window, outside the margins, then
|
||||
// just keep overwriting the last line.
|
||||
if (CUR.Y + wi.CURPOS.Y > BOTTOM)
|
||||
{
|
||||
PCHAR_INFO row = HeapAlloc( hHeap, 0, WIDTH * sizeof(CHAR_INFO) );
|
||||
if (row != NULL)
|
||||
{
|
||||
COORD s, c;
|
||||
SMALL_RECT r;
|
||||
s.X = WIDTH;
|
||||
s.Y = 1;
|
||||
c.X = c.Y = 0;
|
||||
for (r.Top = 0; r.Top <= wi.CURPOS.Y; ++r.Top)
|
||||
{
|
||||
if (r.Top == 0)
|
||||
{
|
||||
r.Left = CUR.X;
|
||||
r.Right = RIGHT;
|
||||
}
|
||||
else if (r.Top == wi.CURPOS.Y)
|
||||
{
|
||||
r.Left = LEFT;
|
||||
r.Right = wi.CURPOS.X - 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
r.Left = LEFT;
|
||||
r.Right = RIGHT;
|
||||
}
|
||||
r.Bottom = r.Top;
|
||||
ReadConsoleOutput( hConWrap, row, s, c, &r );
|
||||
r.Top = r.Bottom = CUR.Y;
|
||||
WriteConsoleOutput( hConOut, row, s, c, &r );
|
||||
if (CUR.Y != BOTTOM)
|
||||
++CUR.Y;
|
||||
}
|
||||
HeapFree( hHeap, 0, row );
|
||||
CloseHandle( hConWrap );
|
||||
nCharInBuffer = nWrapped = 0;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (wi.CURPOS.Y > bot_margin - top_margin)
|
||||
{
|
||||
// The line is bigger than the scroll region, copy that portion.
|
||||
PCHAR_INFO row = HeapAlloc( hHeap, 0, (bot_margin - top_margin + 1)
|
||||
* WIDTH * sizeof(CHAR_INFO) );
|
||||
if (row != NULL)
|
||||
{
|
||||
COORD s, c;
|
||||
SMALL_RECT r;
|
||||
s.X = WIDTH;
|
||||
s.Y = bot_margin - top_margin + 1;
|
||||
c.X = c.Y = 0;
|
||||
r.Left = LEFT;
|
||||
r.Right = RIGHT;
|
||||
r.Bottom = wi.CURPOS.Y;
|
||||
r.Top = r.Bottom - (bot_margin - top_margin);
|
||||
ReadConsoleOutput( hConWrap, row, s, c, &r );
|
||||
r.Top = TOP + top_margin;
|
||||
r.Bottom = TOP + bot_margin;
|
||||
WriteConsoleOutput( hConOut, row, s, c, &r );
|
||||
HeapFree( hHeap, 0, row );
|
||||
CloseHandle( hConWrap );
|
||||
nWrapped = bot_margin - top_margin;
|
||||
nCharInBuffer = 0;
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Scroll the region, then write as normal.
|
||||
SMALL_RECT sr;
|
||||
COORD c;
|
||||
CHAR_INFO ci;
|
||||
|
||||
ci.Char.UnicodeChar = ' ';
|
||||
ci.Attributes = ATTR;
|
||||
c.X =
|
||||
sr.Left = LEFT;
|
||||
sr.Right = RIGHT;
|
||||
sr.Top = TOP + top_margin;
|
||||
sr.Bottom = TOP + bot_margin;
|
||||
c.Y = sr.Top - wi.CURPOS.Y;
|
||||
ScrollConsoleScreenBuffer( hConOut, &sr, &sr, c, &ci );
|
||||
CUR.Y -= wi.CURPOS.Y;
|
||||
SetConsoleCursorPosition( hConOut, CUR );
|
||||
}
|
||||
}
|
||||
nWrapped += wi.CURPOS.Y;
|
||||
CloseHandle( hConWrap );
|
||||
if (im && !nWrapped)
|
||||
{
|
||||
SMALL_RECT sr, cr;
|
||||
CHAR_INFO ci; // unused, but necessary
|
||||
|
||||
sr.Top = sr.Bottom = csbi.dwCursorPosition.Y = here.Y;
|
||||
sr.Left = here.X;
|
||||
sr.Right = csbi.dwSize.X - 1;
|
||||
cr = sr;
|
||||
cr.Left = csbi.dwCursorPosition.X;
|
||||
ScrollConsoleScreenBuffer(hConOut, &sr,&cr, csbi.dwCursorPosition, &ci);
|
||||
cr.Top = cr.Bottom = sr.Top = sr.Bottom = CUR.Y;
|
||||
cr.Right = sr.Right = RIGHT;
|
||||
sr.Left = CUR.X;
|
||||
cr.Left = CUR.X = wi.CURPOS.X;
|
||||
ScrollConsoleScreenBuffer( hConOut, &sr, &cr, CUR, &ci );
|
||||
}
|
||||
if (pState->crm)
|
||||
{
|
||||
@ -654,8 +775,7 @@ void FlushBuffer( void )
|
||||
|
||||
void PushBuffer( WCHAR c )
|
||||
{
|
||||
CONSOLE_SCREEN_BUFFER_INFO csbi;
|
||||
DWORD nWritten;
|
||||
CONSOLE_SCREEN_BUFFER_INFO Info;
|
||||
|
||||
ChPrev = c;
|
||||
|
||||
@ -665,17 +785,17 @@ void PushBuffer( WCHAR c )
|
||||
ChBuffer[nCharInBuffer++] = c;
|
||||
FlushBuffer();
|
||||
// Avoid writing the newline if wrap has already occurred.
|
||||
GetConsoleScreenBufferInfo( hConOut, &csbi );
|
||||
GetConsoleScreenBufferInfo( hConOut, &Info );
|
||||
if (pState->crm)
|
||||
{
|
||||
// If we're displaying controls, then the only way we can be on the left
|
||||
// margin is if wrap occurred.
|
||||
if (csbi.dwCursorPosition.X != 0)
|
||||
WriteConsole( hConOut, L"\n", 1, &nWritten, NULL );
|
||||
if (CUR.X != 0)
|
||||
MoveDown( TRUE );
|
||||
}
|
||||
else
|
||||
{
|
||||
LPCWSTR nl = L"\n";
|
||||
BOOL nl = TRUE;
|
||||
if (nWrapped)
|
||||
{
|
||||
// It's wrapped, but was anything more written? Look at the current
|
||||
@ -684,26 +804,30 @@ void PushBuffer( WCHAR c )
|
||||
// already at the margin, then it was spaces or tabs that caused the
|
||||
// wrap, which can be ignored and overwritten.
|
||||
CHAR_INFO blank;
|
||||
PCHAR_INFO row;
|
||||
row = HeapAlloc( hHeap, 0, csbi.dwSize.X * sizeof(CHAR_INFO) );
|
||||
PCHAR_INFO row = HeapAlloc( hHeap, 0, WIDTH * sizeof(CHAR_INFO) );
|
||||
if (row != NULL)
|
||||
{
|
||||
COORD s, c;
|
||||
SMALL_RECT r;
|
||||
s.X = csbi.dwSize.X;
|
||||
s.X = WIDTH;
|
||||
s.Y = 1;
|
||||
c.X = c.Y = 0;
|
||||
r.Left = 0;
|
||||
r.Right = s.X - 1;
|
||||
r.Top = r.Bottom = csbi.dwCursorPosition.Y;
|
||||
r.Left = LEFT;
|
||||
r.Right = RIGHT;
|
||||
r.Top = r.Bottom = CUR.Y;
|
||||
ReadConsoleOutput( hConOut, row, s, c, &r );
|
||||
blank.Char.UnicodeChar = ' ';
|
||||
blank.Attributes = csbi.wAttributes;
|
||||
blank.Attributes = ATTR;
|
||||
while (*(PDWORD)&row[c.X] == *(PDWORD)&blank)
|
||||
{
|
||||
if (++c.X == s.X)
|
||||
{
|
||||
nl = (csbi.dwCursorPosition.X == 0) ? NULL : L"\r";
|
||||
if (CUR.X != 0)
|
||||
{
|
||||
CUR.X = 0;
|
||||
SetConsoleCursorPosition( hConOut, CUR );
|
||||
}
|
||||
nl = FALSE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -712,7 +836,7 @@ void PushBuffer( WCHAR c )
|
||||
nWrapped = 0;
|
||||
}
|
||||
if (nl)
|
||||
WriteConsole( hConOut, nl, 1, &nWritten, NULL );
|
||||
MoveDown( TRUE );
|
||||
}
|
||||
}
|
||||
else if (c == '\b')
|
||||
@ -721,12 +845,12 @@ void PushBuffer( WCHAR c )
|
||||
FlushBuffer();
|
||||
if (nWrapped)
|
||||
{
|
||||
GetConsoleScreenBufferInfo( hConOut, &csbi );
|
||||
if (csbi.dwCursorPosition.X == 0)
|
||||
GetConsoleScreenBufferInfo( hConOut, &Info );
|
||||
if (CUR.X == 0)
|
||||
{
|
||||
csbi.dwCursorPosition.X = csbi.dwSize.X - 1;
|
||||
csbi.dwCursorPosition.Y--;
|
||||
SetConsoleCursorPosition( hConOut, csbi.dwCursorPosition );
|
||||
CUR.X = RIGHT;
|
||||
CUR.Y--;
|
||||
SetConsoleCursorPosition( hConOut, CUR );
|
||||
--nWrapped;
|
||||
bs = TRUE;
|
||||
}
|
||||
@ -831,20 +955,9 @@ void InterpretEscSeq( void )
|
||||
DWORD mode;
|
||||
SHORT top, bottom;
|
||||
|
||||
#define WIDTH Info.dwSize.X
|
||||
#define HEIGHT Info.dwSize.Y
|
||||
#define CUR Info.dwCursorPosition
|
||||
#define WIN Info.srWindow
|
||||
#define TOP WIN.Top
|
||||
#define BOTTOM WIN.Bottom
|
||||
#define LAST (HEIGHT - 1)
|
||||
#define LEFT 0
|
||||
#define RIGHT (WIDTH - 1)
|
||||
|
||||
#define FillBlank( len, Pos ) \
|
||||
FillConsoleOutputCharacter( hConOut, ' ', len, Pos, &NumberOfCharsWritten );\
|
||||
FillConsoleOutputAttribute( hConOut, Info.wAttributes, len, Pos, \
|
||||
&NumberOfCharsWritten )
|
||||
FillConsoleOutputAttribute( hConOut, ATTR, len, Pos, &NumberOfCharsWritten )
|
||||
|
||||
if (prefix == '[')
|
||||
{
|
||||
@ -862,14 +975,19 @@ void InterpretEscSeq( void )
|
||||
break;
|
||||
|
||||
case 7:
|
||||
awm = (suffix == 'h');
|
||||
mode = cache[0].mode;
|
||||
if (suffix == 'h')
|
||||
if (awm)
|
||||
mode |= ENABLE_WRAP_AT_EOL_OUTPUT;
|
||||
else
|
||||
mode &= ~ENABLE_WRAP_AT_EOL_OUTPUT;
|
||||
SetConsoleMode( hConOut, mode );
|
||||
break;
|
||||
|
||||
case 6:
|
||||
om = (suffix == 'h');
|
||||
break;
|
||||
|
||||
case 95:
|
||||
pState->noclear = (suffix == 'h');
|
||||
break;
|
||||
@ -878,12 +996,15 @@ void InterpretEscSeq( void )
|
||||
{
|
||||
COORD buf;
|
||||
SMALL_RECT win;
|
||||
|
||||
tb_margins = FALSE;
|
||||
|
||||
buf.X = (suffix == 'l') ? pState->buf_width : 132;
|
||||
if (buf.X == 0)
|
||||
break;
|
||||
if (buf.X != 0)
|
||||
{
|
||||
GetConsoleScreenBufferInfo( hConOut, &Info );
|
||||
buf.Y = HEIGHT;
|
||||
win.Left = 0;
|
||||
win.Left = LEFT;
|
||||
win.Top = TOP;
|
||||
win.Bottom = BOTTOM;
|
||||
if (suffix == 'h')
|
||||
@ -909,6 +1030,7 @@ void InterpretEscSeq( void )
|
||||
SetConsoleScreenBufferSize( hConOut, buf );
|
||||
SetConsoleWindowInfo( hConOut, TRUE, &win );
|
||||
}
|
||||
}
|
||||
// Even if the screen is not cleared, scroll in a new window the
|
||||
// first time this is used.
|
||||
if (pState->noclear &&
|
||||
@ -1128,7 +1250,7 @@ void InterpretEscSeq( void )
|
||||
Rect.Bottom = CUR.Y - 1;
|
||||
Pos.X = Pos.Y = 0;
|
||||
CharInfo.Char.UnicodeChar = ' ';
|
||||
CharInfo.Attributes = Info.wAttributes;
|
||||
CharInfo.Attributes = ATTR;
|
||||
ScrollConsoleScreenBuffer(hConOut, &Rect, NULL, Pos, &CharInfo);
|
||||
}
|
||||
SetConsoleWindowInfo( hConOut, TRUE, &WIN );
|
||||
@ -1174,74 +1296,103 @@ void InterpretEscSeq( void )
|
||||
FillBlank( p1, CUR );
|
||||
return;
|
||||
|
||||
case 'r': // ESC[#;#r Set top and bottom margins.
|
||||
if (es_argc == 0 && suffix2 == '+')
|
||||
{
|
||||
tb_margins = FALSE; // ESC[+r == remove margins
|
||||
return;
|
||||
}
|
||||
if (es_argc > 2) return;
|
||||
if (es_argv[1] == 0) es_argv[1] = BOTTOM - TOP + 1;
|
||||
top_margin = p1 - 1;
|
||||
bot_margin = es_argv[1] - 1;
|
||||
if (bot_margin > BOTTOM - TOP) bot_margin = BOTTOM - TOP;
|
||||
if (top_margin >= bot_margin) return; // top must be less than bottom
|
||||
tb_margins = TRUE;
|
||||
set_pos( LEFT, om ? TOP + top_margin : TOP );
|
||||
return;
|
||||
|
||||
case 'S': // ESC[#S Scroll up/Pan down.
|
||||
case 'T': // ESC[#T Scroll down/Pan up.
|
||||
if (es_argc > 1) return; // ESC[S == ESC[1S
|
||||
Pos.X =
|
||||
Rect.Left = LEFT;
|
||||
Rect.Right = RIGHT;
|
||||
if (tb_margins)
|
||||
{
|
||||
Rect.Top = TOP + top_margin;
|
||||
Rect.Bottom = TOP + bot_margin;
|
||||
}
|
||||
else
|
||||
{
|
||||
Rect.Top = top;
|
||||
Rect.Bottom = bottom;
|
||||
}
|
||||
Pos.Y = Rect.Top + (suffix == 'T' ? p1 : -p1);
|
||||
CharInfo.Char.UnicodeChar = ' ';
|
||||
CharInfo.Attributes = ATTR;
|
||||
ScrollConsoleScreenBuffer( hConOut, &Rect, &Rect, Pos, &CharInfo );
|
||||
return;
|
||||
|
||||
case 'L': // ESC[#L Insert # blank lines.
|
||||
if (es_argc > 1) return; // ESC[L == ESC[1L
|
||||
Rect.Left = WIN.Left = LEFT;
|
||||
Rect.Right = WIN.Right = RIGHT;
|
||||
Rect.Top = CUR.Y;
|
||||
Rect.Bottom = bottom;
|
||||
Pos.X = LEFT;
|
||||
Pos.Y = CUR.Y + p1;
|
||||
CharInfo.Char.UnicodeChar = ' ';
|
||||
CharInfo.Attributes = Info.wAttributes;
|
||||
ScrollConsoleScreenBuffer( hConOut, &Rect, &WIN, Pos, &CharInfo );
|
||||
// Technically should home the cursor, but perhaps not expected.
|
||||
return;
|
||||
|
||||
case 'M': // ESC[#M Delete # lines.
|
||||
if (es_argc > 1) return; // ESC[M == ESC[1M
|
||||
Rect.Left = WIN.Left = LEFT;
|
||||
Rect.Right = WIN.Right = RIGHT;
|
||||
if (es_argc > 1) return; // ESC[L == ESC[1L
|
||||
Pos.X =
|
||||
Rect.Left = LEFT;
|
||||
Rect.Right = RIGHT;
|
||||
Rect.Top = CUR.Y;
|
||||
if (tb_margins)
|
||||
{
|
||||
if (CUR.Y < TOP + top_margin || CUR.Y > TOP + bot_margin) return;
|
||||
Rect.Bottom = TOP + bot_margin;
|
||||
}
|
||||
else
|
||||
{
|
||||
Rect.Bottom = bottom;
|
||||
Rect.Top = CUR.Y - p1;
|
||||
Pos.X = LEFT;
|
||||
Pos.Y = TOP = CUR.Y;
|
||||
}
|
||||
Pos.Y = Rect.Top + (suffix == 'L' ? p1 : -p1);
|
||||
CharInfo.Char.UnicodeChar = ' ';
|
||||
CharInfo.Attributes = Info.wAttributes;
|
||||
ScrollConsoleScreenBuffer( hConOut, &Rect, &WIN, Pos, &CharInfo );
|
||||
CharInfo.Attributes = ATTR;
|
||||
ScrollConsoleScreenBuffer( hConOut, &Rect, &Rect, Pos, &CharInfo );
|
||||
// Technically should home the cursor, but perhaps not expected.
|
||||
return;
|
||||
|
||||
case 'P': // ESC[#P Delete # characters.
|
||||
if (es_argc > 1) return; // ESC[P == ESC[1P
|
||||
Rect.Left = WIN.Left = CUR.X;
|
||||
Rect.Right = WIN.Right = RIGHT;
|
||||
Pos.X = CUR.X - p1;
|
||||
Pos.Y =
|
||||
Rect.Top =
|
||||
Rect.Bottom = CUR.Y;
|
||||
CharInfo.Char.UnicodeChar = ' ';
|
||||
CharInfo.Attributes = Info.wAttributes;
|
||||
ScrollConsoleScreenBuffer( hConOut, &Rect, &WIN, Pos, &CharInfo );
|
||||
return;
|
||||
|
||||
case '@': // ESC[#@ Insert # blank characters.
|
||||
if (es_argc > 1) return; // ESC[@ == ESC[1@
|
||||
Rect.Left = WIN.Left = CUR.X;
|
||||
Rect.Right = WIN.Right = RIGHT;
|
||||
Pos.X = CUR.X + p1;
|
||||
Pos.Y =
|
||||
case 'P': // ESC[#P Delete # characters.
|
||||
if (es_argc > 1) return; // ESC[P == ESC[1P
|
||||
Rect.Left = CUR.X;
|
||||
Rect.Right = RIGHT;
|
||||
Rect.Top =
|
||||
Rect.Bottom = CUR.Y;
|
||||
if (suffix == '@')
|
||||
CUR.X += p1;
|
||||
else
|
||||
CUR.X -= p1;
|
||||
CharInfo.Char.UnicodeChar = ' ';
|
||||
CharInfo.Attributes = Info.wAttributes;
|
||||
ScrollConsoleScreenBuffer( hConOut, &Rect, &WIN, Pos, &CharInfo );
|
||||
CharInfo.Attributes = ATTR;
|
||||
ScrollConsoleScreenBuffer( hConOut, &Rect, &Rect, CUR, &CharInfo );
|
||||
return;
|
||||
|
||||
case 'k': // ESC[#k
|
||||
case 'A': // ESC[#A Moves cursor up # lines
|
||||
case 'F': // ESC[#F Moves cursor up # lines, column 1.
|
||||
if (es_argc > 1) return; // ESC[A == ESC[1A
|
||||
Pos.Y = CUR.Y - p1;
|
||||
if (tb_margins && (om || CUR.Y >= TOP + top_margin))
|
||||
top = TOP + top_margin;
|
||||
if (Pos.Y < top) Pos.Y = top;
|
||||
set_pos( CUR.X, Pos.Y );
|
||||
set_pos( (suffix == 'F') ? LEFT : CUR.X, Pos.Y );
|
||||
return;
|
||||
|
||||
case 'e': // ESC[#e
|
||||
case 'B': // ESC[#B Moves cursor down # lines
|
||||
case 'E': // ESC[#E Moves cursor down # lines, column 1.
|
||||
if (es_argc > 1) return; // ESC[B == ESC[1B
|
||||
Pos.Y = CUR.Y + p1;
|
||||
if (tb_margins && (om || CUR.Y <= TOP + bot_margin))
|
||||
bottom = TOP + bot_margin;
|
||||
if (Pos.Y > bottom) Pos.Y = bottom;
|
||||
set_pos( CUR.X, Pos.Y );
|
||||
set_pos( (suffix == 'E') ? LEFT : CUR.X, Pos.Y );
|
||||
return;
|
||||
|
||||
case 'a': // ESC[#a
|
||||
@ -1266,20 +1417,6 @@ void InterpretEscSeq( void )
|
||||
set_pos( Pos.X, CUR.Y );
|
||||
return;
|
||||
|
||||
case 'E': // ESC[#E Moves cursor down # lines, column 1.
|
||||
if (es_argc > 1) return; // ESC[E == ESC[1E
|
||||
Pos.Y = CUR.Y + p1;
|
||||
if (Pos.Y > bottom) Pos.Y = bottom;
|
||||
set_pos( LEFT, Pos.Y );
|
||||
return;
|
||||
|
||||
case 'F': // ESC[#F Moves cursor up # lines, column 1.
|
||||
if (es_argc > 1) return; // ESC[F == ESC[1F
|
||||
Pos.Y = CUR.Y - p1;
|
||||
if (Pos.Y < top) Pos.Y = top;
|
||||
set_pos( LEFT, Pos.Y );
|
||||
return;
|
||||
|
||||
case '`': // ESC[#`
|
||||
case 'G': // ESC[#G Moves cursor column # in current row.
|
||||
if (es_argc > 1) return; // ESC[G == ESC[1G
|
||||
@ -1288,25 +1425,26 @@ void InterpretEscSeq( void )
|
||||
set_pos( Pos.X, CUR.Y );
|
||||
return;
|
||||
|
||||
case 'f': // ESC[#;#f
|
||||
case 'H': // ESC[#;#H Moves cursor to line #, column #
|
||||
if (es_argc > 2) return; // ESC[H == ESC[1;1H ESC[#H == ESC[#;1H
|
||||
CUR.X = p2 - 1;
|
||||
if (CUR.X > RIGHT) CUR.X = RIGHT;
|
||||
--es_argc; // so we can fall through
|
||||
|
||||
case 'd': // ESC[#d Moves cursor row #, current column.
|
||||
if (es_argc > 1) return; // ESC[d == ESC[1d
|
||||
if (tb_margins && om)
|
||||
{
|
||||
top = TOP + top_margin;
|
||||
bottom = TOP + bot_margin;
|
||||
}
|
||||
Pos.Y = top + p1 - 1;
|
||||
if (Pos.Y < top) Pos.Y = top;
|
||||
if (Pos.Y > bottom) Pos.Y = bottom;
|
||||
set_pos( CUR.X, Pos.Y );
|
||||
return;
|
||||
|
||||
case 'f': // ESC[#;#f
|
||||
case 'H': // ESC[#;#H Moves cursor to line #, column #
|
||||
if (es_argc > 2) return; // ESC[H == ESC[1;1H ESC[#H == ESC[#;1H
|
||||
Pos.X = p2 - 1;
|
||||
if (Pos.X > RIGHT) Pos.X = RIGHT;
|
||||
Pos.Y = top + p1 - 1;
|
||||
if (Pos.Y < top) Pos.Y = top;
|
||||
if (Pos.Y > bottom) Pos.Y = bottom;
|
||||
set_pos( Pos.X, Pos.Y );
|
||||
return;
|
||||
|
||||
case 'g':
|
||||
if (es_argc > 1) return; // ESC[g == ESC[0g
|
||||
switch (es_argv[0])
|
||||
@ -1661,7 +1799,7 @@ void InterpretEscSeq( void )
|
||||
}
|
||||
|
||||
|
||||
void ScrollDown( void )
|
||||
void MoveDown( BOOL home )
|
||||
{
|
||||
CONSOLE_SCREEN_BUFFER_INFO Info;
|
||||
SMALL_RECT Rect;
|
||||
@ -1669,7 +1807,32 @@ void ScrollDown( void )
|
||||
CHAR_INFO CharInfo;
|
||||
|
||||
GetConsoleScreenBufferInfo( hConOut, &Info );
|
||||
if (CUR.Y == LAST)
|
||||
if (tb_margins && CUR.Y == TOP + bot_margin)
|
||||
{
|
||||
Rect.Left = LEFT;
|
||||
Rect.Right = RIGHT;
|
||||
Rect.Top = TOP + top_margin + 1;
|
||||
Rect.Bottom = TOP + bot_margin;
|
||||
Pos.X = LEFT;
|
||||
Pos.Y = TOP + top_margin;
|
||||
CharInfo.Char.UnicodeChar = ' ';
|
||||
CharInfo.Attributes = ATTR;
|
||||
ScrollConsoleScreenBuffer( hConOut, &Rect, NULL, Pos, &CharInfo );
|
||||
if (home)
|
||||
{
|
||||
CUR.X = 0;
|
||||
SetConsoleCursorPosition( hConOut, CUR );
|
||||
}
|
||||
}
|
||||
else if (tb_margins && CUR.Y == BOTTOM)
|
||||
{
|
||||
if (home)
|
||||
{
|
||||
CUR.X = 0;
|
||||
SetConsoleCursorPosition( hConOut, CUR );
|
||||
}
|
||||
}
|
||||
else if (CUR.Y == LAST)
|
||||
{
|
||||
Rect.Left = LEFT;
|
||||
Rect.Right = RIGHT;
|
||||
@ -1677,17 +1840,23 @@ void ScrollDown( void )
|
||||
Rect.Bottom = LAST;
|
||||
Pos.X = Pos.Y = 0;
|
||||
CharInfo.Char.UnicodeChar = ' ';
|
||||
CharInfo.Attributes = Info.wAttributes;
|
||||
CharInfo.Attributes = ATTR;
|
||||
ScrollConsoleScreenBuffer( hConOut, &Rect, NULL, Pos, &CharInfo );
|
||||
if (home)
|
||||
{
|
||||
CUR.X = 0;
|
||||
SetConsoleCursorPosition( hConOut, CUR );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (home) CUR.X = 0;
|
||||
++CUR.Y;
|
||||
SetConsoleCursorPosition( hConOut, CUR );
|
||||
}
|
||||
}
|
||||
|
||||
void ScrollUp( void )
|
||||
void MoveUp( void )
|
||||
{
|
||||
CONSOLE_SCREEN_BUFFER_INFO Info;
|
||||
SMALL_RECT Rect;
|
||||
@ -1695,16 +1864,32 @@ void ScrollUp( void )
|
||||
CHAR_INFO CharInfo;
|
||||
|
||||
GetConsoleScreenBufferInfo( hConOut, &Info );
|
||||
if (CUR.Y == 0)
|
||||
if (tb_margins && CUR.Y == TOP + top_margin)
|
||||
{
|
||||
Rect.Left = LEFT;
|
||||
Rect.Right = RIGHT;
|
||||
Rect.Top = TOP + top_margin;
|
||||
Rect.Bottom = TOP + bot_margin - 1;
|
||||
Pos.X = LEFT;
|
||||
Pos.Y = TOP + top_margin + 1;
|
||||
CharInfo.Char.UnicodeChar = ' ';
|
||||
CharInfo.Attributes = ATTR;
|
||||
ScrollConsoleScreenBuffer( hConOut, &Rect, NULL, Pos, &CharInfo );
|
||||
}
|
||||
else if (tb_margins && CUR.Y == TOP)
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
else if (CUR.Y == 0)
|
||||
{
|
||||
Rect.Left = LEFT;
|
||||
Rect.Right = RIGHT;
|
||||
Rect.Top = 0;
|
||||
Rect.Bottom = LAST - 1;
|
||||
Pos.X = 0;
|
||||
Pos.X = LEFT;
|
||||
Pos.Y = 1;
|
||||
CharInfo.Char.UnicodeChar = ' ';
|
||||
CharInfo.Attributes = Info.wAttributes;
|
||||
CharInfo.Attributes = ATTR;
|
||||
ScrollConsoleScreenBuffer( hConOut, &Rect, NULL, Pos, &CharInfo );
|
||||
}
|
||||
else
|
||||
@ -1821,13 +2006,13 @@ ParseAndPrintString( HANDLE hDev,
|
||||
else if (c == 'D') // IND Index
|
||||
{
|
||||
FlushBuffer();
|
||||
ScrollDown();
|
||||
MoveDown( FALSE );
|
||||
state = 1;
|
||||
}
|
||||
else if (c == 'M') // RI Reverse Index
|
||||
{
|
||||
FlushBuffer();
|
||||
ScrollUp();
|
||||
MoveUp();
|
||||
state = 1;
|
||||
}
|
||||
else if (c == 'H') // HTS Character Tabulation Set
|
||||
@ -1846,7 +2031,7 @@ ParseAndPrintString( HANDLE hDev,
|
||||
GetConsoleScreenBufferInfo( hConOut, &Info );
|
||||
pState->SavePos = CUR;
|
||||
pState->SaveSgr = pState->sgr;
|
||||
pState->SaveAttr = Info.wAttributes;
|
||||
pState->SaveAttr = ATTR;
|
||||
SaveG0 = G0_special;
|
||||
state = 1;
|
||||
}
|
||||
@ -3182,13 +3367,13 @@ HookFn Hooks[] = {
|
||||
void OriginalAttr( PVOID lpReserved )
|
||||
{
|
||||
HANDLE hConOut;
|
||||
CONSOLE_SCREEN_BUFFER_INFO csbi;
|
||||
CONSOLE_SCREEN_BUFFER_INFO Info;
|
||||
|
||||
hConOut = CreateFile( L"CONOUT$", GENERIC_READ | GENERIC_WRITE,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
||||
NULL, OPEN_EXISTING, 0, NULL );
|
||||
if (!GetConsoleScreenBufferInfo( hConOut, &csbi ))
|
||||
csbi.wAttributes = 7;
|
||||
if (!GetConsoleScreenBufferInfo( hConOut, &Info ))
|
||||
ATTR = 7;
|
||||
|
||||
// If we were loaded dynamically, remember the current attributes to restore
|
||||
// upon unloading. However, if we're the 64-bit DLL, but the image is 32-
|
||||
@ -3202,7 +3387,7 @@ void OriginalAttr( PVOID lpReserved )
|
||||
pNTHeader = MakeVA( PIMAGE_NT_HEADERS, pDosHeader->e_lfanew );
|
||||
if (pNTHeader->FileHeader.Machine == IMAGE_FILE_MACHINE_AMD64)
|
||||
#endif
|
||||
orgattr = csbi.wAttributes;
|
||||
orgattr = ATTR;
|
||||
GetConsoleMode( hConOut, &orgmode );
|
||||
GetConsoleCursorInfo( hConOut, &orgcci );
|
||||
}
|
||||
|
@ -91,7 +91,7 @@
|
||||
use -pu to unload from the parent.
|
||||
*/
|
||||
|
||||
#define PDATE L"19 December, 2017"
|
||||
#define PDATE L"21 December, 2017"
|
||||
|
||||
#include "ansicon.h"
|
||||
#include "version.h"
|
||||
|
12
readme.txt
12
readme.txt
@ -181,11 +181,14 @@ Sequences Recognised
|
||||
\e[?3l DECCOLM Selecting 80 or 132 Columns per Page (prior)
|
||||
\e[?95h DECNCSM No Clearing Screen On Column Change Mode (keep)
|
||||
\e[?95l DECNCSM No Clearing Screen On Column Change Mode (clear)
|
||||
\e[?6h DECOM Origin Mode (top margin)
|
||||
\e[?6l DECOM Origin Mode (top line)
|
||||
\e[#;#;#...,~ DECPS Play Sound
|
||||
\e8 DECRC Restore Cursor
|
||||
\e7 DECSC Save Cursor
|
||||
\e[?5W DECST8C Set Tab at Every 8 Columns
|
||||
\e[?5;#W DECST8C Set Tab at Every # Columns (ANSICON extension)
|
||||
\e[#;#r DECSTBM Set Top and Bottom Margins
|
||||
\e[?25h DECTCEM Text Cursor Enable Mode (show cursor)
|
||||
\e[?25l DECTCEM Text Cursor Enable Mode (hide cursor)
|
||||
\e[#M DL Delete Line
|
||||
@ -212,6 +215,8 @@ Sequences Recognised
|
||||
\e(0 SCS Select Character Set (DEC special graphics)
|
||||
\e(B SCS Select Character Set (ASCII)
|
||||
\e[#;#;#m SGR Select Graphic Rendition
|
||||
\e[#T SD Scroll Down/Pan Up
|
||||
\e[#S SU Scroll Up/Pan Down
|
||||
\e[#g TBC Tabulation Clear
|
||||
\e[#d VPA Line Position Absolute
|
||||
\e[#k VPB Line Position Backward
|
||||
@ -312,7 +317,7 @@ Version History
|
||||
|
||||
Legend: + added, - bug-fixed, * changed.
|
||||
|
||||
1.80 - 19 December, 2017:
|
||||
1.80 - 21 December, 2017:
|
||||
- fix unloading;
|
||||
- fix -e et al when redirecting to CON;
|
||||
- hook CreateFile and CreateConsoleScreenBuffer to force read/write access
|
||||
@ -336,7 +341,8 @@ Version History
|
||||
+ added IND, NEL, RI, DA, DECCOLM, DECNCSM, DECSC & DECRC;
|
||||
+ added SCS, but only for special/ASCII (same as Win10);
|
||||
+ added tab handling (HT, HTS, TBC & DECST8C);
|
||||
+ added IRM.
|
||||
+ added IRM;
|
||||
+ added DECOM, DECSTBM, SD & SU.
|
||||
|
||||
1.72 - 24 December, 2015:
|
||||
- handle STD_OUTPUT_HANDLE & STD_ERROR_HANDLE in WriteFile;
|
||||
@ -565,4 +571,4 @@ Distribution
|
||||
|
||||
|
||||
==============================
|
||||
Jason Hood, 19 December, 2017.
|
||||
Jason Hood, 21 December, 2017.
|
||||
|
@ -152,6 +152,16 @@ H set tab stop
|
||||
7 save cursor position (buffer only), attributes and G0 character set
|
||||
8 restore above (if nothing was saved only moves cursor to top-left)
|
||||
|
||||
[+r remove top and bottom margins
|
||||
[r set top and bottom margins to the window
|
||||
[#r set top margin to line #, bottom margin to the window
|
||||
[#;#r set top margin to line #, bottom margin to line #
|
||||
|
||||
[S scroll up (pan down) one line
|
||||
[#S scroll up (pan down) # lines
|
||||
[T scroll down (pan up) one line
|
||||
[#T scroll down (pan up) # lines
|
||||
|
||||
(0 select the DEC Special Graphics Character Set
|
||||
(B select ASCII
|
||||
|
||||
@ -161,6 +171,8 @@ H set tab stop
|
||||
[4l replace characters
|
||||
[?3h set 132 columns
|
||||
[?3l restore original columns
|
||||
[?6h set origin to top margin
|
||||
[?6l set origin to top line
|
||||
[?7h wrap lines at screen edge
|
||||
[?7l don't wrap lines at screen edge
|
||||
[?25h show cursor
|
||||
|
Loading…
x
Reference in New Issue
Block a user