读取控制台调色板的 RGB 值

Reading the RGB values of the console color palette

本文关键字:RGB 调色板 控制台 读取      更新时间:2023-10-16

在 C 或 C++ 中,有没有办法直接读取调色板 RGB 值?特别有趣的是 xterm(和其他(用于定义多达 256 种终端颜色的扩展颜色空间。

土豆

这方面的例子是,我想定义自己的颜色(使用 ANSI 转义序列,如 e]4;3;rgb:cc/78/33e\ 或直接在 c 中(,但我需要在重新定义用户颜色之前保存它们(万一他们已经重新定义了他们的颜色(,以便我可以在我的程序完成时恢复它们。用户设置不好。

现在,我的目标是使用 ANSI 转义序列以客户端方式执行此操作。但是由于我找不到如何去除颜色,因此我开始考虑在 c 或 c++ 中执行此操作。

该解决方案将被编写为具有本机扩展(基本上是嵌入式 c 或 c ++ 代码(的 ruby gem,我的目标是获得一个跨平台的解决方案,即使主要目标是 OS X,其次是 Linux 环境......

索斯

从最初的实验开始,我已经到了可以为调色板中的代码点定义任何颜色的地步。我还可以轻松恢复默认的系统颜色(因为它们是 ANSI 标准(。我已经在ANSI转义码中寻找一种方法来做到这一点,但没有找到。我认为这保存在内存中的某个地方,如果有任何方法可以找到位置,阅读颜色应该很容易......

甜点

总结到目前为止评论中的信息:

看起来唯一能始终如一地做到这一点的方法就是以不同的颜色打印 █ 个字符的屏幕并抓取其中的颜色。由于这个项目应该是跨平台的三个主要操作系统,并且由于Linux目前有3个显示管理器在用户使用中,而Windows有两个(7和8(,我只能想象那将是:)

所以我的"解决方案"™是只破坏用户的颜色(如果他们有系统默认值以外的任何东西......这,让我们面对这是非常罕见的(。我将提供一个设置文件,用户可以告诉插件如果他们对系统默认值不满意,应该恢复什么颜色。务实而无聊,但它让我再次继续:)

[编辑 1] 抱歉,这不会导致解决方案,但对于其他人,我添加了 DAC 调色板 IO 访问

查看旧的传统 EGA/VGA 参考...

  • 您可以通过 I/O 访问调色板
  • 我认为是端口0x03C8,0x03C9十六进制。
  • 当然,在现代操作系统中,您无法访问它
  • 因此,请在DOS-BOX或其他方法中尝试并保存原始调色板值,它们应该是相同的。

对于直接访问,请尝试以下操作:

BYTE r,g,b,c=5; // R,G,B values are 6 bit only !!!
out 0x3C8,c;    // set color index to work with <0,255>
in  r,0x3C9;    // read color pallete for color c
in  g,0x3C9;    // not sure if it should be r,g,b 
in  b,0x3C9;    // or b,g,r ... i did not use it for too many years
out 0x3C8,c;    // set color index to work with <0,255>
out 0x3C9,r;    // write color pallete for color c
out 0x3C9,g;
out 0x3C9,b;

C/C++ 没有 in、out 操作,因此请使用以下命令:

BYTE i,o;       // this must be local !!!
WORD port;      // this must be local !!!
asm {
    mov dx,port // in i,port
    in al,dx
    mov o,al
    mov dx,port // out port,o
    mov al,o
    out dx,al
    }

使用 xterm(以及一些相似的(,您可以使用转义序列来获取调色板。 这记录在 XTerm 控制序列中:

OSC Ps ;Pt ST

设置文本参数。 某些控制序列返回信息:
Ps = 4 ;c ;规范 ⇒ 将颜色编号 c 更改为规范指定的颜色。
如果给出的是"?">而不是名称或 RGB 规范,xterm以相同形式的控制序列进行回复,该可用于设置相应的颜色。 因为不止一对色号和规格可以一对给出控制序列,XTERM可以做出多个回复。

这样做可能会很慢。 xterm 提供了用于在堆栈上操作调色板的转义序列:

CSI pm # P
将当前动态调色板和 ANSI 调色板颜色推送到堆栈上(XTPUSHCOLORS(,xterm。 参数(范围为 1 的整数通过 10,因为默认 0 将推送(可用于将调色板存储到堆栈中,而无需推送。

CSI Pm # Q
用于设置动态调色板和 ANSI 调色板颜色的弹出堆栈(XTPOPCOLORS(,xterm。 参数(范围为 1 的整数到 10,因为默认的 0 会弹出(可用于从堆栈中恢复调色板而不弹出。

iTerm2 和 Windows 终端的更改日志表明它们支持这些 xterm 功能。

/* Hi -- I think this C code will reveal all that you need to do all that you asked.  Best wishes...*/
/*--------------------------------------------------------------------------
 CONSOLE_LEGACY_PALETTE.C
 Code by Greg Spears 
 Created 2022.10.22 and released into the public domain.
 Tested, use at your own risk.
---------------------------------------------------------------------------*/
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
/* This is what the palette used to be before it was updated by Microsoft in 2017.*/
BYTE legacy_palette[16][3] = {
{0,0,0 },
{0,0,128},
{0,128,0},
{0,128,128},
{128,0,0},
{128,0,128},
{128,128,0},
{192,192,192},
{128,128,128},
{0,0,255},
{0,255,0},
{0,255,255},
{255,0,0},
{255,0,255},
{255,255,0},
{255,255,255}
};
/* Used for displaying the color palette by printf()*/
static char *szTextColors[] = {
"BLACK",
"BLUE",
"GREEN",
"CYAN",
"RED",
"MAGENTA",
"BROWN",
"LIGHTGRAY",
"DARKGRAY",
"LIGHTBLUE",
"LIGHTGREEN",
"LIGHTCYAN",
"LIGHTRED",
"LIGHTMAGENTA",
"YELLOW",
"WHITE"
};

/*--------------------------------------------------------------------------
set_legacy_palette()
DATE:       REASON:
2022.10.22 - Created 
Params: none
Returns: TRUE if the console palette updates successfully.  FALSE if not.
---------------------------------------------------------------------------*/
int set_legacy_palette(void)
{
    CONSOLE_SCREEN_BUFFER_INFOEX csbix;
    int iii;
    HANDLE hConOut = GetStdHandle(STD_OUTPUT_HANDLE);
    if(!hConOut)
    {
        printf("set_legacy_palette():  bad handle: hConOut");
        return FALSE;
    }
    /* Use GetConsoleScreenBufferInfoEx() to get the console palette*/
    csbix.cbSize = sizeof(csbix);
    if(!GetConsoleScreenBufferInfoEx(hConOut, &csbix))
    {
        printf("GetConsoleScreenBufferInfoEx() failed!");
        return FALSE;
    }
    printf("printing color palette: --------------------------n");
    for (iii = 0; iii < 16; iii++)
        printf("ColorTable[%d] =  t%-12s [%3d,%3d,%3d]n", iii, szTextColors[iii], 
            GetRValue(csbix.ColorTable[iii]), 
            GetGValue(csbix.ColorTable[iii]), 
            GetBValue(csbix.ColorTable[iii]));
    printf("--------------------------------------------------n");
    /* Fill the palette strcuture with legacy RGB values*/
    for(iii = 0; iii < 16; iii++)
        csbix.ColorTable[iii] = 
            RGB(legacy_palette[iii][0], legacy_palette[iii][1], legacy_palette[iii][2]);
    /* use SetConsoleScreenBufferInfoEx() to send the updated palette to the OS.
    */
    if (!SetConsoleScreenBufferInfoEx(hConOut, &csbix))
    {
        printf("set_legacy_palette(): SetConsoleScreenBufferInfoEx() failed!");
        return FALSE;
    }
    return TRUE;
}