12

Using curses in python you can easily use the default color scheme for the terminal using:

curses.use_default_colors()

However once you try to recolor any character, using a color pair you have to declare a background color:

curses.init_pair(1, curses.COLOR_RED, curses.COLOR_BLACK)

I really don't want to change the background from the default but I would like to change the foreground.

Is there any way to either get the default background color? or to change just the foreground color?

I am aware that I could use ANSI escape codes to adjust just the foreground color, however ANSI codes are not compatible with curses and I would rather work with curses than rewrite everything in ANSI codes.

Wheat Wizard
  • 3,982
  • 14
  • 34

2 Answers2

22

Ok, I figured it out,

If you call init_pair with -1 as a value it will fill in the terminal default. For example to make red text with the default background:

curses.init_pair(1, curses.COLOR_RED, -1)

Now curses.color_pair(1) will be set to the background. This will even work if you change the terminal's default while the program is running.

You do have to call curses.use_default_colors() first to use this.

Wheat Wizard
  • 3,982
  • 14
  • 34
  • 1
    So you can use -1 to set the foreground/background to the default color, but is it possible to get the *actual color* used for the background? Basically I want to know: is the default background black or blue or white or red or what? – dthor Feb 06 '20 at 17:50
  • 1
    @dthor I suspect that it is not possible. Terminals backgrounds don't necessarily need to be a uniform color. – Wheat Wizard Feb 06 '20 at 18:21
1

window.inch(0,0) will return a value from reading the character at position (0,0) of the window that includes the attributes at that location. If you use stdscr as the window you should get the current colors for the whole screen. Quoting the official documentation:

"Return the character at the given position in the window. The bottom 8 bits are the character proper, and upper bits are the attributes."

colors = stdscr.inch(0,0) & curses.A_COLOR

should extract the current colors for both foreground and background. Separating the foreground and background colors is something I am currently trying to figure out myself but haven't had much luck yet. On a Windows machine the curses implementation is PDCurses, and the source code for PDCurses seems to say that the two colors are combined in the leftmost byte of a 4-byte integer field, but I haven't confirmed that yet.

There is also window.getbkgd() which the documentation says will:

"Return the given window’s current background character/attribute pair."

which is more than a little vague. I am working on nailing down exactly what that function actually returns, though it sounds a lot like the value returned from the inch function.

HTH

Peter

[Edit] This sequence of curses calls reliably gives you the foreground and background color numbers. On *ix systems the defaults are fg=-1 and bg=-1 (-1 means "default" to the init_color() function) but on windows (python 3.8+, windows-curses 2.2.0) the default values are fg=7 (COLOR_WHITE) and bg=0 (COLOR_BLACK).

    attr = stdscr.getbkgd()
    stdscr.addstr("scrbkgd={:08X}={}\n".format(attr, attr))
    pair = curses.pair_number(attr)
    if platform.system() == "Windows":
        pair = pair >> 16
    fg, bg = curses.pair_content (pair)
    stdscr.addstr("color(scrbkgd) fg={:08X}={},bg={:08X}={}\n".format(fg, fg, bg, bg))
    stdscr.getch()
pjfarley3
  • 29
  • 2