Add palette sequences
Recognise the xterm ESC]4 & ESC]104 OSC commands to set/reset colors. Three color specs are recognised: `#RGB`, `#RRGGBB` and `R,G,B`; in addition, multiple specs can be given (separated by commas) to automatically increase the index. I also allow `*` to query this index and all subsequent ones. Reset will restore the colors from when the DLL was first loaded, not from the Console Properties.
This commit is contained in:
parent
9fbe42a583
commit
e2f9b4e417
248
ANSI.c
248
ANSI.c
@ -152,7 +152,7 @@
|
|||||||
remove wcstok, avoiding potential interference with the host;
|
remove wcstok, avoiding potential interference with the host;
|
||||||
similarly, use a private heap instead of malloc.
|
similarly, use a private heap instead of malloc.
|
||||||
|
|
||||||
v1.80, 26 October to 23 November, 2017:
|
v1.80, 26 October to 29 November, 2017:
|
||||||
fix unloading;
|
fix unloading;
|
||||||
revert back to (re)storing buffer cursor position;
|
revert back to (re)storing buffer cursor position;
|
||||||
increase cache to five handles;
|
increase cache to five handles;
|
||||||
@ -163,7 +163,8 @@
|
|||||||
use the system default sound for the bell;
|
use the system default sound for the bell;
|
||||||
add DECPS Play Sound;
|
add DECPS Play Sound;
|
||||||
use intermediate byte '+' to use buffer, not window;
|
use intermediate byte '+' to use buffer, not window;
|
||||||
ESC followed by a control character will display that character.
|
ESC followed by a control character will display that character;
|
||||||
|
added palette sequences.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "ansicon.h"
|
#include "ansicon.h"
|
||||||
@ -287,8 +288,8 @@ const BYTE backgroundcolor[8] =
|
|||||||
BACKGROUND_WHITE, // white background
|
BACKGROUND_WHITE, // white background
|
||||||
};
|
};
|
||||||
|
|
||||||
const BYTE attr2ansi[8] = // map console attribute to ANSI number
|
const BYTE attr2ansi[16] = // map console attribute to ANSI number
|
||||||
{
|
{ // or vice versa
|
||||||
0, // black
|
0, // black
|
||||||
4, // blue
|
4, // blue
|
||||||
2, // green
|
2, // green
|
||||||
@ -296,21 +297,50 @@ const BYTE attr2ansi[8] = // map console attribute to ANSI number
|
|||||||
1, // red
|
1, // red
|
||||||
5, // magenta
|
5, // magenta
|
||||||
3, // yellow
|
3, // yellow
|
||||||
7 // white
|
7, // white
|
||||||
|
8, // bright black
|
||||||
|
12, // bright blue
|
||||||
|
10, // bright green
|
||||||
|
14, // bright cyan
|
||||||
|
9, // bright red
|
||||||
|
13, // bright magenta
|
||||||
|
11, // bright yellow
|
||||||
|
15, // bright white
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct _CONSOLE_SCREEN_BUFFER_INFOX {
|
||||||
|
ULONG cbSize;
|
||||||
|
COORD dwSize;
|
||||||
|
COORD dwCursorPosition;
|
||||||
|
WORD wAttributes;
|
||||||
|
SMALL_RECT srWindow;
|
||||||
|
COORD dwMaximumWindowSize;
|
||||||
|
WORD wPopupAttributes;
|
||||||
|
BOOL bFullscreenSupported;
|
||||||
|
COLORREF ColorTable[16];
|
||||||
|
} CONSOLE_SCREEN_BUFFER_INFOX, *PCONSOLE_SCREEN_BUFFER_INFOX;
|
||||||
|
|
||||||
|
typedef BOOL (WINAPI *PHCSBIX)(
|
||||||
|
HANDLE hConsoleOutput,
|
||||||
|
PCONSOLE_SCREEN_BUFFER_INFOX lpConsoleScreenBufferInfoEx
|
||||||
|
);
|
||||||
|
|
||||||
|
PHCSBIX GetConsoleScreenBufferInfoX, SetConsoleScreenBufferInfoX;
|
||||||
|
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
BYTE foreground; // ANSI base color (0 to 7; add 30)
|
BYTE foreground; // ANSI base color (0 to 7; add 30)
|
||||||
BYTE background; // ANSI base color (0 to 7; add 40)
|
BYTE background; // ANSI base color (0 to 7; add 40)
|
||||||
BYTE bold; // console FOREGROUND_INTENSITY bit
|
BYTE bold; // console FOREGROUND_INTENSITY bit
|
||||||
BYTE underline; // console BACKGROUND_INTENSITY bit
|
BYTE underline; // console BACKGROUND_INTENSITY bit
|
||||||
BYTE rvideo; // swap foreground/bold & background/underline
|
BYTE rvideo; // swap foreground/bold & background/underline
|
||||||
BYTE concealed; // set foreground/bold to background/underline
|
BYTE concealed; // set foreground/bold to background/underline
|
||||||
BYTE reverse; // swap console foreground & background attributes
|
BYTE reverse; // swap console foreground & background attributes
|
||||||
BYTE crm; // showing control characters?
|
BYTE crm; // showing control characters?
|
||||||
COORD SavePos; // saved cursor position
|
COORD SavePos; // saved cursor position
|
||||||
|
COLORREF palette[16];
|
||||||
} STATE, *PSTATE;
|
} STATE, *PSTATE;
|
||||||
|
|
||||||
PSTATE pState;
|
PSTATE pState;
|
||||||
@ -325,7 +355,8 @@ void get_state( void )
|
|||||||
HWND hwnd;
|
HWND hwnd;
|
||||||
BOOL init;
|
BOOL init;
|
||||||
HANDLE hConOut;
|
HANDLE hConOut;
|
||||||
CONSOLE_SCREEN_BUFFER_INFO csbi;
|
CONSOLE_SCREEN_BUFFER_INFO csbi;
|
||||||
|
CONSOLE_SCREEN_BUFFER_INFOX csbix;
|
||||||
static STATE state; // on the odd chance file mapping fails
|
static STATE state; // on the odd chance file mapping fails
|
||||||
|
|
||||||
if (pState != NULL)
|
if (pState != NULL)
|
||||||
@ -362,7 +393,16 @@ void get_state( void )
|
|||||||
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 );
|
||||||
if (!GetConsoleScreenBufferInfo( hConOut, &csbi ))
|
csbix.cbSize = sizeof(csbix);
|
||||||
|
if (GetConsoleScreenBufferInfoX &&
|
||||||
|
GetConsoleScreenBufferInfoX( hConOut, &csbix ))
|
||||||
|
{
|
||||||
|
csbi.dwSize = csbix.dwSize;
|
||||||
|
csbi.wAttributes = csbix.wAttributes;
|
||||||
|
csbi.srWindow = csbix.srWindow;
|
||||||
|
memcpy( pState->palette, csbix.ColorTable, sizeof(csbix.ColorTable) );
|
||||||
|
}
|
||||||
|
else if (!GetConsoleScreenBufferInfo( hConOut, &csbi ))
|
||||||
{
|
{
|
||||||
DEBUGSTR( 1, "Failed to get screen buffer info (%u) - assuming defaults",
|
DEBUGSTR( 1, "Failed to get screen buffer info (%u) - assuming defaults",
|
||||||
GetLastError() );
|
GetLastError() );
|
||||||
@ -641,6 +681,21 @@ void SendSequence( LPTSTR seq )
|
|||||||
HeapFree( hHeap, 0, in );
|
HeapFree( hHeap, 0, in );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void send_palette_sequence( COLORREF c )
|
||||||
|
{
|
||||||
|
BYTE r, g, b;
|
||||||
|
TCHAR buf[16];
|
||||||
|
|
||||||
|
r = GetRValue( c );
|
||||||
|
g = GetGValue( c );
|
||||||
|
b = GetBValue( c );
|
||||||
|
if ((c & 0x0F0F0F) == ((c & 0xF0F0F0) >> 4))
|
||||||
|
wsprintf( buf, L"#%X%X%X", r & 0xF, g & 0xF, b & 0xF );
|
||||||
|
else
|
||||||
|
wsprintf( buf, L"#%02X%02X%02X", r, g, b );
|
||||||
|
SendSequence( buf );
|
||||||
|
}
|
||||||
|
|
||||||
// ========== Print functions
|
// ========== Print functions
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
@ -742,7 +797,7 @@ void InterpretEscSeq( void )
|
|||||||
// that's what we do. According to T.416 (ISO 8613-6), there is
|
// that's what we do. According to T.416 (ISO 8613-6), there is
|
||||||
// only one parameter, which is divided into elements. So where
|
// only one parameter, which is divided into elements. So where
|
||||||
// xterm does "38;2;R;G;B" it should really be "38;2:I:R:G:B" (I is
|
// xterm does "38;2;R;G;B" it should really be "38;2:I:R:G:B" (I is
|
||||||
// a colour space identifier).
|
// a color space identifier).
|
||||||
if (i+1 < es_argc)
|
if (i+1 < es_argc)
|
||||||
{
|
{
|
||||||
if (es_argv[i+1] == 2) // rgb
|
if (es_argv[i+1] == 2) // rgb
|
||||||
@ -1211,14 +1266,154 @@ void InterpretEscSeq( void )
|
|||||||
else // (prefix == ']')
|
else // (prefix == ']')
|
||||||
{
|
{
|
||||||
// Ignore any "private" sequences.
|
// Ignore any "private" sequences.
|
||||||
if (prefix2 != 0)
|
if (prefix2 != 0 || es_argc != 1)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (es_argc == 1 && (es_argv[0] == 0 || // ESC]0;titleST - icon (ignored) &
|
if (es_argv[0] == 0 || // ESC]0;titleST - icon (ignored) &
|
||||||
es_argv[0] == 2)) // ESC]2;titleST - window
|
es_argv[0] == 2) // ESC]2;titleST - window
|
||||||
{
|
{
|
||||||
SetConsoleTitle( Pt_arg );
|
SetConsoleTitle( Pt_arg );
|
||||||
}
|
}
|
||||||
|
else if (es_argv[0] == 4 || // ESC]4;paletteST - set/get color(s)
|
||||||
|
es_argv[0] == 104) // ESC]104;paletteST - reset color(s)
|
||||||
|
{
|
||||||
|
CONSOLE_SCREEN_BUFFER_INFOX csbix;
|
||||||
|
csbix.cbSize = sizeof(csbix);
|
||||||
|
if (!GetConsoleScreenBufferInfoX ||
|
||||||
|
!GetConsoleScreenBufferInfoX( hConOut, &csbix ))
|
||||||
|
return;
|
||||||
|
if (es_argv[0] == 4)
|
||||||
|
{
|
||||||
|
BYTE r, g, b;
|
||||||
|
DWORD c;
|
||||||
|
LPTSTR beg, end;
|
||||||
|
BOOL started = FALSE;
|
||||||
|
for (beg = Pt_arg;; beg = end + 1)
|
||||||
|
{
|
||||||
|
i = (int)wcstoul( beg, &end, 10 );
|
||||||
|
if (end == beg || (*end != ';' && *end != '\0') || i >= 16)
|
||||||
|
break;
|
||||||
|
if (end[2] == ';' || end[2] == '\0')
|
||||||
|
{
|
||||||
|
if (end[1] == '*')
|
||||||
|
{
|
||||||
|
SendSequence( L"\33]4;" );
|
||||||
|
end[1] = '\0';
|
||||||
|
SendSequence( beg );
|
||||||
|
for (; i < 16; ++i)
|
||||||
|
{
|
||||||
|
send_palette_sequence( csbix.ColorTable[attr2ansi[i]] );
|
||||||
|
SendSequence( (i == 15) ? L"\a" : L"," );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (end[1] == '?')
|
||||||
|
{
|
||||||
|
if (!started)
|
||||||
|
{
|
||||||
|
SendSequence( L"\33]4" );
|
||||||
|
started = TRUE;
|
||||||
|
}
|
||||||
|
SendSequence( L";" );
|
||||||
|
end[1] = '\0';
|
||||||
|
SendSequence( beg );
|
||||||
|
send_palette_sequence( csbix.ColorTable[attr2ansi[i]] );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
end += (end[2] == '\0') ? 1 : 2;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (started)
|
||||||
|
{
|
||||||
|
started = FALSE;
|
||||||
|
SendSequence( L"\a" );
|
||||||
|
}
|
||||||
|
for (beg = end + 1;; beg = end + 1)
|
||||||
|
{
|
||||||
|
BOOL valid;
|
||||||
|
if (*beg == '#')
|
||||||
|
{
|
||||||
|
valid = TRUE;
|
||||||
|
c = (DWORD)wcstoul( ++beg, &end, 16 );
|
||||||
|
if (end - beg == 3)
|
||||||
|
{
|
||||||
|
r = (BYTE)(c >> 8);
|
||||||
|
g = (BYTE)(c >> 4) & 0xF;
|
||||||
|
b = (BYTE)c & 0xF;
|
||||||
|
r |= r << 4;
|
||||||
|
g |= g << 4;
|
||||||
|
b |= b << 4;
|
||||||
|
}
|
||||||
|
else if (end - beg == 6)
|
||||||
|
{
|
||||||
|
r = (BYTE)(c >> 16);
|
||||||
|
g = (BYTE)(c >> 8);
|
||||||
|
b = (BYTE)c;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
valid = FALSE;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
valid = FALSE;
|
||||||
|
c = (DWORD)wcstoul( beg, &end, 10 );
|
||||||
|
if (*end == ',' && c < 256)
|
||||||
|
{
|
||||||
|
r = (BYTE)c;
|
||||||
|
c = (DWORD)wcstoul( end + 1, &end, 10 );
|
||||||
|
if (*end == ',' && c < 256)
|
||||||
|
{
|
||||||
|
g = (BYTE)c;
|
||||||
|
c = (DWORD)wcstoul( end + 1, &end, 10 );
|
||||||
|
if ((*end == ',' || *end == ';' || *end == '\0') && c < 256)
|
||||||
|
{
|
||||||
|
b = (BYTE)c;
|
||||||
|
valid = TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (valid)
|
||||||
|
csbix.ColorTable[attr2ansi[i++]] = RGB( r, g, b );
|
||||||
|
if (*end != ',' || i == 16)
|
||||||
|
{
|
||||||
|
while (*end != ';' && *end != '\0')
|
||||||
|
++end;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (*end != ';')
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (started)
|
||||||
|
SendSequence( L"\a" );
|
||||||
|
}
|
||||||
|
else // (es_argv[0] == 104)
|
||||||
|
{
|
||||||
|
// Reset each index, or the entire palette.
|
||||||
|
if (Pt_len == 0)
|
||||||
|
memcpy( csbix.ColorTable, pState->palette, sizeof(csbix.ColorTable) );
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LPTSTR beg, end;
|
||||||
|
for (beg = Pt_arg;; beg = end + 1)
|
||||||
|
{
|
||||||
|
i = (int)wcstoul( beg, &end, 10 );
|
||||||
|
if (end == beg || (*end != ';' && *end != '\0') || i >= 16)
|
||||||
|
break;
|
||||||
|
i = attr2ansi[i];
|
||||||
|
csbix.ColorTable[i] = pState->palette[i];
|
||||||
|
if (*end == '\0')
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
++csbix.srWindow.Right;
|
||||||
|
++csbix.srWindow.Bottom;
|
||||||
|
SetConsoleScreenBufferInfoX( hConOut, &csbix );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1384,6 +1579,12 @@ ParseAndPrintString( HANDLE hDev,
|
|||||||
{
|
{
|
||||||
state = 1;
|
state = 1;
|
||||||
}
|
}
|
||||||
|
else if (prefix == ']')
|
||||||
|
{
|
||||||
|
es_argc++;
|
||||||
|
state = 5;
|
||||||
|
goto state5;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
es_argc++;
|
es_argc++;
|
||||||
@ -1394,6 +1595,7 @@ ParseAndPrintString( HANDLE hDev,
|
|||||||
}
|
}
|
||||||
else if (state == 5)
|
else if (state == 5)
|
||||||
{
|
{
|
||||||
|
state5:
|
||||||
if (c == BEL)
|
if (c == BEL)
|
||||||
{
|
{
|
||||||
Pt_arg[Pt_len] = '\0';
|
Pt_arg[Pt_len] = '\0';
|
||||||
@ -2647,6 +2849,11 @@ BOOL WINAPI DllMain( HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved )
|
|||||||
if (dwReason == DLL_PROCESS_ATTACH)
|
if (dwReason == DLL_PROCESS_ATTACH)
|
||||||
{
|
{
|
||||||
hHeap = HeapCreate( 0, 0, 128 * 1024 );
|
hHeap = HeapCreate( 0, 0, 128 * 1024 );
|
||||||
|
hKernel = GetModuleHandleA( APIKernel );
|
||||||
|
GetConsoleScreenBufferInfoX = (PHCSBIX)GetProcAddress(
|
||||||
|
hKernel, "GetConsoleScreenBufferInfoEx" );
|
||||||
|
SetConsoleScreenBufferInfoX = (PHCSBIX)GetProcAddress(
|
||||||
|
hKernel, "SetConsoleScreenBufferInfoEx" );
|
||||||
|
|
||||||
*logstr = '\0';
|
*logstr = '\0';
|
||||||
GetEnvironmentVariable( L"ANSICON_LOG", logstr, lenof(logstr) );
|
GetEnvironmentVariable( L"ANSICON_LOG", logstr, lenof(logstr) );
|
||||||
@ -2662,7 +2869,6 @@ BOOL WINAPI DllMain( HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved )
|
|||||||
DEBUGSTR( 1, "hDllInstance = %p", hDllInstance );
|
DEBUGSTR( 1, "hDllInstance = %p", hDllInstance );
|
||||||
|
|
||||||
// Get the entry points to the original functions.
|
// Get the entry points to the original functions.
|
||||||
hKernel = GetModuleHandleA( APIKernel );
|
|
||||||
for (hook = Hooks; hook->name; ++hook)
|
for (hook = Hooks; hook->name; ++hook)
|
||||||
hook->oldfunc = GetProcAddress( hKernel, hook->name );
|
hook->oldfunc = GetProcAddress( hKernel, hook->name );
|
||||||
|
|
||||||
|
@ -90,7 +90,7 @@
|
|||||||
write newline with _putws, not putwchar (fixes redirecting to CON).
|
write newline with _putws, not putwchar (fixes redirecting to CON).
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define PDATE L"24 November, 2017"
|
#define PDATE L"29 November, 2017"
|
||||||
|
|
||||||
#include "ansicon.h"
|
#include "ansicon.h"
|
||||||
#include "version.h"
|
#include "version.h"
|
||||||
|
10
readme.txt
10
readme.txt
@ -152,6 +152,8 @@ Sequences Recognised
|
|||||||
|
|
||||||
\e]0;titleBEL xterm: Set window's title (and icon, ignored)
|
\e]0;titleBEL xterm: Set window's title (and icon, ignored)
|
||||||
\e]2;titleBEL xterm: Set window's title
|
\e]2;titleBEL xterm: Set window's title
|
||||||
|
\e]4;...BEL xterm: Change color(s)
|
||||||
|
\e]104;...BEL xterm: Reset color(s)
|
||||||
\e[21t xterm: Report window's title
|
\e[21t xterm: Report window's title
|
||||||
\e[s ANSI.SYS: Save Cursor Position
|
\e[s ANSI.SYS: Save Cursor Position
|
||||||
\e[u ANSI.SYS: Restore Cursor Position
|
\e[u ANSI.SYS: Restore Cursor Position
|
||||||
@ -283,6 +285,7 @@ Limitations
|
|||||||
|
|
||||||
Tabs are fixed at eight columns.
|
Tabs are fixed at eight columns.
|
||||||
The saved position will not be restored correctly if the buffer scrolls.
|
The saved position will not be restored correctly if the buffer scrolls.
|
||||||
|
Palette sequences only work from Vista.
|
||||||
|
|
||||||
There may be a conflict with NVIDIA's drivers, requiring the setting of the
|
There may be a conflict with NVIDIA's drivers, requiring the setting of the
|
||||||
Environment Variable:
|
Environment Variable:
|
||||||
@ -298,7 +301,7 @@ Version History
|
|||||||
|
|
||||||
Legend: + added, - bug-fixed, * changed.
|
Legend: + added, - bug-fixed, * changed.
|
||||||
|
|
||||||
1.80 - 24 November, 2017:
|
1.80 - 29 November, 2017:
|
||||||
- fix unloading;
|
- fix unloading;
|
||||||
- fix -e et al when redirecting to CON;
|
- fix -e et al when redirecting to CON;
|
||||||
- hook CreateFile and CreateConsoleScreenBuffer to force read/write access
|
- hook CreateFile and CreateConsoleScreenBuffer to force read/write access
|
||||||
@ -310,7 +313,8 @@ Version History
|
|||||||
* escape control characters;
|
* escape control characters;
|
||||||
+ use the system default sound for the bell;
|
+ use the system default sound for the bell;
|
||||||
+ added Play Sound DECPS;
|
+ added Play Sound DECPS;
|
||||||
+ added '+' intermediate byte to use the buffer, rather than the window.
|
+ added '+' intermediate byte to use the buffer, rather than the window;
|
||||||
|
+ added palette sequences.
|
||||||
|
|
||||||
1.72 - 24 December, 2015:
|
1.72 - 24 December, 2015:
|
||||||
- handle STD_OUTPUT_HANDLE & STD_ERROR_HANDLE in WriteFile;
|
- handle STD_OUTPUT_HANDLE & STD_ERROR_HANDLE in WriteFile;
|
||||||
@ -539,4 +543,4 @@ Distribution
|
|||||||
|
|
||||||
|
|
||||||
=============================
|
=============================
|
||||||
Jason Hood, 24 November, 2017.
|
Jason Hood, 29 November, 2017.
|
||||||
|
@ -131,6 +131,18 @@ whilst "[2+J" will erase the buffer).
|
|||||||
]2;TitleST
|
]2;TitleST
|
||||||
sets the console title to "Title"; ST (string terminator) is either
|
sets the console title to "Title"; ST (string terminator) is either
|
||||||
character 7 (BEL) or escape and backslash
|
character 7 (BEL) or escape and backslash
|
||||||
|
]4;#;spec,spec...;#...ST
|
||||||
|
set or query the palette:
|
||||||
|
# is the ANSI index (0-7, or 8-15 for bold/underline)
|
||||||
|
spec is:
|
||||||
|
? send the current value to console input
|
||||||
|
* send the current and all subsequent values
|
||||||
|
#RGB set the color (hexadecimal)
|
||||||
|
#RRGGBB set the color (hexadecimal)
|
||||||
|
R,G,B set the color (decimal)
|
||||||
|
]104ST restore the entire palette
|
||||||
|
]104;#...ST
|
||||||
|
restore the color of each index
|
||||||
|
|
||||||
[#;#;#...,~
|
[#;#;#...,~
|
||||||
play sound (beep):
|
play sound (beep):
|
||||||
|
Loading…
x
Reference in New Issue
Block a user