I would like to know how to get the cursor position (x, y) in my program, without writing anything on the screen neither tracking it all the time.
I found out a way to get its position with this function (I don't check the return of read, write, etc here to write a smaller code on this subject but I do it in my program):
void get_cursor_position(int *col, int *rows)
{
int a = 0;
int i = 0;
char buf[4];
write(1, "\033[6n", 4); // string asking for the cursor position
read(1, buf, 4);
while (buf[i])
{
if (buf[i] >= 48 && buf[i] <= 57)
{
if (a == 0)
*rows = atoi(&buf[i]) - 1;
else
*col = atoi(&buf[i]) - 1;
a++;
}
i++;
}
}
This function gives me the exact cursor position (*rows = y, *col = x), but it writes on the screen.
How can I get the cursor position without writing anything on the screen?
(If the cursor is on one of the printed characters, it will overwrite it.)
Should echo be toggled before and after sending the escape sequence?
This is a school project, so I only can use termcap, I can't use ncurses functions, the only allowed functions are tputs, tgoto, tgetstr, tgetnum, tgetflag.
There are several problems:
canonical mode is buffered (see below)
the read
is done on the file-descriptor for standard output (that may happen to work — sometimes — but don't count on it)
the read
does not read enough characters to get a typical response
the response would have two decimal integers, separated by semicolon ;
the response would have a final character (which would become an issue if the read
actually asked for enough characters...)
Further reading:
In canonical mode input processing, terminal input is processed in units of lines. A line is delimited by a newline character (
NL
), an end-of-file character (EOF
), or an end-of-line (EOL
) character. See Special Characters for more information onEOF
andEOL
. This means that aread
request will not return until an entire line has been typed or a signal has been received. Also, no matter how many bytes are requested in the read() call, at most one line will be returned. It is not, however, necessary to read a whole line at once; any number of bytes, even one, may be requested in a read() without losing information.
CSI Ps n Device Status Report (DSR). Ps = 5 -> Status Report. Result ("OK") is CSI 0 n Ps = 6 -> Report Cursor Position (CPR) [row;column]. Result is CSI r ; c R
That is, your program should be prepared to read Escape[
followed by two decimal integers (with no fixed limit on their length), and two other characters ;
and R
.
By the way, termcap by itself will do little for your solution. While ncurses has some relevant capabilities defined in the terminal database:
# u9 terminal enquire string (equiv. to ANSI/ECMA-48 DA)
# u8 terminal answerback description
# u7 cursor position request (equiv. to VT100/ANSI/ECMA-48 DSR 6)
# u6 cursor position report (equiv. to ANSI/ECMA-48 CPR)
few programs use those, and in any case you would find it difficult to use the cursor position report in a termcap application.