Does ncurses support TrueColor? - c

I know that ncurses supports 16-bit colors with the init_pair function and friends. But is it possible to display characters in full RGB color (aka True Color)?

The ncurses FAQ Why only 16 (or 256) colors? goes into some detail, giving the history of this feature, pointing out that the proper term is direct color (since that is based on a standard, while true color is in other places said to be a special case of direct color). Likewise, the xterm FAQ Can I set a color by its number? provides corresponding detail on the history of this feature in xterm.
ncurses 6.1 (January 2018) introduced support for direct color, as illustrated in a recap of the ncurses versus slang history. That includes an example program picsmap which uses the RGB extension (documented in user_caps(5)).
Because the number of colors in 24-bit RGB is larger than the range of numbers supported in the original (signed!) 16-bit numbers (see term(5)), it was necessary to provide for larger numbers. ncurses 6.1 does this with minimal change to existing applications by adding to the opaque TERMINAL structure, and adding functions which can manipulate the extended numbers. It was not necessary to change the ABI (currently 6 since August 2015), because none of the documented features changed their binary interface.
To use the RGB feature in ncurses it is necessary to have the proper terminal description. xterm-direct is used for xterm. This example sets the RGB flag and overrides the color features (but reserves the first 8 ANSI colors, making it a workable hybrid):
xterm+direct|xterm with direct-color indexing,
RGB,
colors#0x1000000, pairs#0x10000, CO#8,
initc#, op=\E[39;49m,
setab=\E[%?%p1%{8}%<%t4%p1%d%e48\:2\:\:%p1%{65536}%/%d\:%p1
%{256}%/%{255}%&%d\:%p1%{255}%&%d%;m,
setaf=\E[%?%p1%{8}%<%t3%p1%d%e38\:2\:\:%p1%{65536}%/%d\:%p1
%{256}%/%{255}%&%d\:%p1%{255}%&%d%;m,
setb#, setf#,
Other terminals have their corresponding flavors. Because the feature is documented, with examples, it is possible for others to customize terminal descriptions as needed.
picsmap is one of the test-programs for ncurses, which is available separately as "ncurses-examples". Tutorials are off-topic; the source-code is readily available.

“True Color” is a bit of a misnomer—it does not exist.
Ncurses lets you redefine the values of the standard 16 colors, but does not support arbitrary RBG colors at arbitrary positions. Fortunately, many terminals do support 8-bit RGB (sometimes called “true color”) if you wish to do it yourself—to be clear, this means not using ncurses.
The sequences are:
ESC[ 38;2;⟨r⟩;⟨g⟩;⟨b⟩ m: Select RGB foreground color
ESC[ 48;2;⟨r⟩;⟨g⟩;⟨b⟩ m: Select RGB background color
(From ANSI Escape Code)
Here, “ESC” is just the character ‘\x1b’ and you replace r, g, and b with values from 0-255. Something like this:
printf("\x1b[38;2;%d,%d,%dm", r, g, b);
This does not work on all terminals but there are plenty that do support it.
Why Not Ncurses?
Why doesn’t Ncurses support this? It turns out that Ncurses is not just a library for styling text and placing it at different locations on the terminal, but it also tries to be clever and minimize the amount of data transmitted over stdout when the on-screen text changes. Ncurses does this by keeping its own text buffer internally, and transmitting deltas over stdout.
This is a really nice feature to have if you’re running over a 14.4 kbit/s modem or a slow serial connection back in 1993, back when Ncurses was originally made. However, Ncurses has made an implementation tradeoff of not supporting additional colors.

Related

Is it possible to print rgb colours in C

I want to print out the block character(█) as any rgb colour(#000000-#ffffff). I'm aware of the ANSI colours and the ANSI 8-bit however the colours are to limited for my use. How can I best achieve full RBG color range on terminal?
This will only be used for UNIX/UNIX like OS, there will be no windows use.
Unless you use a custom/non-standard terminal emulator, all eventual libraries will be based on the ANSI control sequences. If that is not sufficient for your use, you should consider making a gui application. Also as #KamilCuk pointed out in the comments, the ANSI colors are not limited to 8 bits but to 24 bits, which allows you to specify any (#000000-#ffffff) color.
If you are designing a command line UI, you should also keep in mind, that not all people use a "white font on black background" terminal color scheme. While you can achieve "cool" color effects with the 24 bit colors, I would encourage you to respect the users color scheme choice and stick to the 3 and 4 bit colors (described in this section). If you do that, your command line program will be much more likely to look and work well even on terminals with a light colorscheme.

How to not change the colors in other terminal programs?

I found an old game I wrote using ncurses. I noticed that after closing the game and running another ncurses based program, the colours had changed for that program as well. This is entirely expected behaviour that I wasn't aware of when I wrote the game several years ago.
Since ncurses doesn't know the initial palette, there is no way to reset the palette to its initial values after quitting the game. With this in mind, what is the best way to deal with colours in ncurses?
Here's what I've considered:
Only override colours that are higher up in the palette. If you start changing colours from position 0, it's very likely that you will change colours that other programs are using. If you start at 100 (for instance), it's much less likely that your changes will interfere with another program. I suppose not changing the 16 colour ANSI palette is the key here.
Manually inspect the default palette and choose default colours that fit the game. Besides being cumbersome and perhaps not letting you set the exact colour you want, there is no guarantee that the default palette will be the same on all systems. There might be a library to automatically get the corresponding xterm colour. It seems like https://github.com/vim-scripts/CSApprox is doing something like that. I would assume that most modern systems will run terminals with the same palette, so it might be fine, depending on what systems you are targeting. The default palette of xterm is available here: https://jonasjacek.github.io/colors/
Use color_content to get the original colour. I tried it and it didn't work. ncurses can only get the colour content of colours that were set by init_color.
Restore the palette to the default xterm palette. I suppose if the terminal supports 256 colours, there's a good chance that it is using the default xterm palette. However, the user might have changed it, so it might still interfere with the users configuration.
Use API specific to xterm or other terminal emulator for getting colours. I don't know if any such API exists, but it would be a potential solution, with the major drawback that it will only support that specific terminal emulator.
I might implement both 1 and 2, and let the user choose the behaviour by passing a flag. I don't know of any terminal programs that use rich colours, so not sure how many programs out there actually face this problem, but there's bound to be at least a few. If you have any examples of how other programs deal with this, that would be very helpful.
From https://invisible-island.net/ncurses/ncurses.faq.html:
If your terminal description does not contain the orig_pair or orig_colors capability, you will be unable to reset colors to the pre-curses state. This happens, for example, with aixterm.
However, if your terminal does support resetting colors to a default state, ncurses will use this when exiting Curses mode. Terminal types that do this include the Linux console, rxvt and the XFree86 xterm.
To find out if your terminal can reset the colors, run:
infocmp -L | grep orig
Mine can only reset pairs and not colors. I haven't found an API to check this from the program itself, but there's no real reason to check it unless you've implemented multiple ways of dealing with colors. I have, by the way, and I'm not happy with either.
I tried overriding colors higher up in the palette and I still managed to change colors for other programs. I still think it's sensible to avoid the 16 first colors, but it seems like there are no colors that you can safely change.
I also tried using the default colors from https://jonasjacek.github.io/colors/, but I couldn't get the effect I wanted. I could probably simplify the theme and still make it look nice, but I couldn't replicate the look I was going for.
It seems like the best solution is to make a nice looking theme with the default colors, unless that isn't possible, in which case you will just have to accept that other programs might not look great as a result. It's not too difficult to open a new terminal anyway, and that will get your colors sorted again.

How do i use more than 8 colors in ncurses?

I just started to use ncurses on Linux. I wanted to use more than 8 colors, but there were only 8 available.
How can I use more colors, or create my own by giving them a names, and set their RGB values?
I tried editing a color with init_color, but that will simply replace one of the current 8 instead of creating new ones.
Note: the value of the global var COLORS is 256, so I believe I can use up to 256 different colors.
If your terminal supports it, you should choose (or customize) a terminal description which has more than 8 colors. As it is, there are a lot of existing terminal descriptions which could be used: most are customized for particular terminals (or terminal emulators).
If your terminal supports it, the corresponding description would have the capability initc. That is used by the library call init_color. The xterm-256color entry has this for instance:
initc=\E]4;%p1%d;rgb\:%p2%{255}%*%{1000}%/%2.2X/%p3%{255}%*%{1000}%/%2.2X/%p4%{255}%*%{1000}%/%2.2X\E\\,
which tells the library how to translate the three parameters into an escape sequence. The terminal entries are built up from reusable parts such as xterm+256color, because some terminals lack the feature you are interested in. For those, xterm+256setaf is appropriate.
For reference,
Terminal Database Most systems have this as base (small) and extra (large) packages.
start_color, init_pair, init_color, has_colors, can_change_color, color_content, pair_content, COLOR_PAIR - curses color manipulation routines
My terminal doesn't recognize color
Why only 16 (or 256) colors?
The constant COLOR_PAIRS defines how many colour pairs a system will allow. See:
http://pubs.opengroup.org/onlinepubs/7908799/xcurses/can_change_color.html.
You can substitute your own numbers in init_color to define new ones. eg init_color(9, 800, 700, 600);

Do modern terminals generally render all utf-8 characters correctly?

I am writting an application in C that will be ran in a terminal, and it would be handy but not necesary to use some of the less used unicode characters. From my experimentation, I have not had any trouble rendering them. However, I would not use any non ascii characters if it were a likely source of trouble in the future.
So, in short, can I count on just about any terminal or terminal emulator in the modern *nix world (mainly linux, freebsd, and osx) to properly render arbitrary utf-8 characters?
If I cannot make such an assumption, there are particular subsets of unicode characters defined for various purposes, so would some such subset at least be reliably rendered in any likely modern *nix terminal or terminal emulator?
NOTE: When I say arbitrary, I do mean arbitrary: any unicode characters. But for completeness of my question, I will note that I am primarily interested in arrows and mathematical characters, this link has lists of both: https://en.wikipedia.org/wiki/Unicode_symbols.
No, you should not assume that. Even in a modern system, the set of fonts installed, the font used by the terminal application, and environment variables such as LANG, LC_*, etc. may influence whether certain characters can be displayed correctly on the terminal or not.
You might be able to make reasonable guesses based on the value of the TERM, LANG, and LC_* environment variable as to what is supported, but it's still going to be a guess. I'd suggest either not relying on it at all or providing some means of enabling/disabling the use (via an environment variable and/or via commandline flags to the application).
For the most part, this depends on the font, not the terminal. But there are a couple of things the terminal software has to take into account. For example, halfwidth and fullwidth forms of CJK characters.
Also, Unicode characters are added on a regular basis. There's no way that every font and terminal software is automatically updated as soon as a new version of the Unicode standard is released.
In general, you should assume that there are always Unicode characters that are not rendered correctly, even on a modern terminal.

Background c program for keyboard mapping

I have installed a Bramma TTF file in my windows 8 system. Through a windows character map, I was able to find individual character code. Attached below the screenshot of the map. We can see at the right bottom side, the character code for "!" is 0x21. Similarly, I can find all the character code of all other letters.
Now I defined a character mapping for this font with my US based keyboard layout. For example, I mapped physical character 'a' in the keyboard to the character shown in 3rd row and 1st column. [whenever I hit 'a' from the keyboard, the corresponding character has to be displayed]
I would like to write a background C program such that it listens the keyboard hit and as per my previously defined character mapping, my C program should output that mapped character. i.e., when i hit character 'a' from the keyboard it should return the mapped character.
Can any one help me out in solving this problem or else just give me a lead towards the solution.
I'm somewhat familiar with these kind of fonts, they popped up in other questions at SO. The kind of questions from users that tried to deal with the consequences of using such a font. They are rather grave.
The biggest problem is that this font is not Unicode compatible. The actual string that underlies the text that's rendered to the screen is very different, containing characters from the ANSI character set. What goes horribly wrong is when the program that displays these strings saves the data. The data file contains the original strings, a good example is an Excel spreadsheet. This spreadsheet just contains gibberish when it is read by any other program. Especially bad when read by a program on another machine that doesn't have the same font installed. Very, very painful.
You are in fact making this problem worse by even destroying the normal mapping between keyboard to ANSI character. The 1st character in the 3rd row is produced by typing a capital I (eye) on the keyboard.
The message is clear: don't do this. Windows supports Unicode compatible fonts with Indic scripts well, fonts like Sylfaen, Mangal, Latha. All of which are available on my Windows 8 machine, about ten thousand miles away from where they are normally used. It also has Indic keyboard layouts available under the Language applet, I just picked one as an example:
Well, it is your funeral. You don't have to write a C program to translate these keystrokes, you need a custom keyboard layout. It is a DLL. You normally need the DDK to build them, but there is simple tooling available to auto-generate them. It doesn't get any easier than with MKLC, the Microsoft Keyboard Layout Creator. Web page and download link are here.
Probably you should use autohotkey.
With this application, you can listen to a set of keys, & then send a different set of keys.
This can be used as implementation of "autocorrect"
e.g.
:*:btw::By the way `
will autocorrect btw to By the way.
autohotkey supports quite complicated scripts, & many scripts are already available online.
On another note, if you only want english keyboard to print malayalam unicode characters, you may also think of a popular software called baraha
Google's Virtual Keyboard (also works with your physical keyboard)
https://code.google.com/apis/ajax/playground/#virtual_keyboard
http://www.tavultesoft.com/ allows you to create keyboards for MSWindows and the web. Over 1000 keyboards are readily provided. There is a developer and a user version. With the developer version you may create installation programs which install fonts, keyboards, keymaps and documentation.

Resources