...making Linux just a little more fun!

Cursor Appearance in the Linux Console

By Anonymous

Escape sequences to control the cursor appearance in the Linux console (text, no X11) are yet to be included in the manpage on console_codes, but they are tentatively documented in the file

/usr/src/linux/Documentation/VGA-softcursor.txt

This article is mainly an interpreted version of the file above, with examples added. The file was written in 1999; if you read it, you'll understand why it needs interpretation.

The following files are also relevant:

/usr/src/linux/drivers/char/vt.c
/usr/src/linux/include/linux/console-struct.h

the first of which is, unfortunately, quite tough to digest.

(1) Hardware vs. Software Cursor

The Linux cursor is, by default, the normal PC text-mode cursor. It looks like a short blinking underscore, whitish on black, with weak contrast in daylight. This is the hardware cursor, i.e., it is generated by the hardware.

However, Linux has the ability to manipulate the cursor appearance using, e.g., a software-generated non-blinking full block cursor. This is done with the escape sequence

    \e[?p1;p2;p3;c

where \e is the escape character, and p1, p2 and p3 are parameters. The last semi-colon is optional. It is used here to tell the sequence closing letter 'c' from the parameters. If you omit any of the parameters, they will default to zero. Only decimals are accepted, and you will never get an error: your input is going to be restrained to the valid range.

Each console can have its own custom softcursor.

(2) Parameters

Parameter 3 sets the colour bits in the VGA adapter's register, parameter 2 toggles the colour bits, and setting goes before toggling. What that means in practice we'll have to find out.

Parameter 1 specifies cursor size as follows:

0   default
1   invisible
2   underscore
3   lower_third
4   lower_half
5   two_thirds
6   full block

The size refers to the character cell at the cursor. As an example, issuing

    echo -e "\e[?3c"

from the command line will turn the cursor into a thick underscore, reclaiming one third of the character cell.

Values 7-15 are also accepted, but they give the same as 6. The cursor default is defined in console-struct.h as the underscore, so, by default, value 0 is same as value 2.

If the first parameter is less than 16, parameters 2 and 3 will be set to 0, and you get the hardware cursor, whitish on black. If visible, it will blink.

As for size, the good news is that parameter 1 really works. The bad news is that parameter 2 and 3 depend in part on VGA peculiarities likely to be implemented differently from graphic adapter to graphic adapter. It can be assumed that the kernel contributors were coding according to the official VGA standard, but that rarely used VGA specifications are implemented in a non-standard way.

A softcursor is obtained setting parameter 1 to 16. Values 17-31 are same as 16. A softcursor is a non-blinking full block in some colour.

For instance, let's try

echo -e "\e[?16c"

We see nothing. How come? Very simple - the cursor is now a block of one full character cell. Parameter 2 and 3 are missing, so they default to 0. That block uses colour 0, which is black. Black on black, gives what? That's what you are seeing.

Lesson learnt: if we want to see the softcursor, we must specify parameter 2 and 3 in a suitable way. Let's try again:

echo -e "\e[?16;0;16c"

You can go through the entire range of colours (0-7), leaving the second parameter at 0 and setting the third parameter to a multiple of 16, or rather a multiple with factor 1-7. Factor 0 already taught us a lesson. Only dim colours will obtain.

So far, so good. We can get a blinking cursor in differing sizes; its colour will be the foreground colour in the console. We can get a non-blinking cursor in (dim) colours, independently of foreground and background colours in the console.

(3) Surprises

The values you enter for parameter 1 are reduced modulo 32. That means 0-31, 32-63, 64-95 ... are the same. However:

48-63   (range 16-31 plus 32)
	gives a softcursor using the console foreground colour,
	making the character at the cursor invisible

112-127 (range 16-31 plus 32 plus 64)
	gives a softcursor using the console foreground colour
	but allowing the character at the cursor to be read

Try the following:

    (i)     echo -e "\e[?48c"
    (ii)    echo -e "\e[?112c"

Note that you are not specifying parameters 2 and 3. If you do, the parameters will apply.

Also note that a bold foreground colour will be dimmed when used as background by the softcursor. So if you changed the console default to bold white on black, both (i) and (ii) will give a dim white non-blinking block.

If you try to get some interesting cursor just firing off wild parameters, be assured that your options are limited, and you will be wasting plenty of time for nothing. Essentially, what you have got to remember is:

parameter 3 determines the softcursor background,
parameter 2 determines the softcursor foreground.

This rule, however, is not 100% correct, since parameter 3 does affect the dim/bold status of the foreground. For instance, let's try the range 64-79 with parameter 2 fixed at 0. The softcursor background is in this case red. What changes when the parameter runs through the range 64-79 is how the character at the cursor shows up.

We are starting from the defaults dim white on black and issue

    echo -e "\e[?16;0;64c"

The cursor background is red; the character at the cursor is dim white. We go up from 64 to 71, and the result is the same. However, for 72-79, the character at the cursor is turned bold; we have bold white on red.

The result is simple: with parameter 2 fixed at 0, parameter 3 will have

    dim  foreground for  16*k + l    (l is 0-7)
    bold foreground for  16*k + l    (l is 8-15)

where k runs from 1-7.

Fine, but what if we keep parameter 3 fixed and let parameter 2 run? In our example, we keep parameter 3 at 64, and let parameter 2 go through 1-15. The result is cursor foreground in different colours, while the background does not change.

This is the maximum you can aspire to. The softcursor's own foreground and background can be different from foreground and background in the console, showing you four colours at all times.

(4) Delusions

You have dutifully read VGA-softcursor.txt, and something caught your attention. Apparently, with the softcursor you can

    [ ... ] highbright the cursor character and still keep the original
    hardware cursor visible.

Well, no - or at least, it depends. The authors were not aware that their hardware was behaving its own way. Compare with the following, where the author clearly warns that what he is saying applies to his ATI Mach 64 card:

    echo -e '\033[?18;255;8c' -- .... if this doesn't get your
    attention, I don't know what will... (nonblinking 'transparent'
    block... blinking the character it's over - over an underline
    that blinks at twice the rate....)

Source:
https://lists.ibiblio.org/pipermail/baslinux/2006-April/010157.html

(5) Mystery

Are we done yet? That would seem to be the case, but for a crash I experienced recently.

A small text-mode application crashed, and left behind a console with white on black and a blinking cursor underscore. That blinking underscore was red; yes, it was red!

Now, there is absolutely no trace on the Web of a hardware cursor with its own very private colour. Of course, I cannot prove it, but, after a couple of hours googling, I would take any bet. Furthermore, the official wisdom states:

    On the standard VGA, the [hardware] cursor color is obtained
    from the foreground color of the character that the cursor is
    superimposing. On the standard VGA, there is no way to modify
    this behavior.

Source: FreeVGA Project
https://www.stanford.edu/class/cs140/projects/pintos/specs/freevga/vga/textcur.htm

So here is my request for support:

Tux