I\'m trying to retrieve the coordinates of cursor in a VT100 terminal using the following code:
void getCursor(int* x, int* y) {
printf(\"\\033[6n\");
s
I ask for the cursor position. If I do not have answer after 100ms (this is arbitrary) I suppose the console is not ansi.
/* This function tries to get the position of the cursor on the terminal.
It can also be used to detect if the terminal is ANSI.
Return 1 in case of success, 0 otherwise.*/
int console_try_to_get_cursor_position(int* x, int *y)
{
fd_set readset;
int success = 0;
struct timeval time;
struct termios term, initial_term;
/*We store the actual properties of the input console and set it as:
no buffered (~ICANON): avoid blocking
no echoing (~ECHO): do not display the result on the console*/
tcgetattr(STDIN_FILENO, &initial_term);
term = initial_term;
term.c_lflag &=~ICANON;
term.c_lflag &=~ECHO;
tcsetattr(STDIN_FILENO, TCSANOW, &term);
//We request position
print_escape_command("6n");
fflush(stdout);
//We wait 100ms for a terminal answer
FD_ZERO(&readset);
FD_SET(STDIN_FILENO, &readset);
time.tv_sec = 0;
time.tv_usec = 100000;
//If it success we try to read the cursor value
if (select(STDIN_FILENO + 1, &readset, NULL, NULL, &time) == 1)
if (scanf("\033[%d;%dR", x, y) == 2) success = 1;
//We set back the properties of the terminal
tcsetattr(STDIN_FILENO, TCSADRAIN, &initial_term);
return success;
}
#include <stdlib.h>
#include <stdio.h>
#include <conio.h>
void readCoord(void* row, void* col){
int i = 0;
char* input = malloc(10);
printf("\e[6n");
while(!_kbhit()) _sleep(1);
while(_kbhit()) *(input + (i++)) = getch();
*(input + i) = '\0';
sscanf(input, "\e[%d;%dR", row, col);
}
void main(void){
int i = 0, r, c;
char* coord = malloc(10);
printf("Hello");
readCoord(&r , &c);
printf("\nYour coordinate is (%d, %d)", c, r);
}
_kbhit()
is used to detect input (DSR are treated as though typed at the keyboard), and
getch()
to read and remove the character from standard input
This program relies on conio.h
, which is not a standard and hence not recommended for portable C programs.
I believe that you really get the expected response in stdin. But imagine what happens actually:
To avoid this use a getc()
(==fgetc(stdin)
) loop instead. If you encounter an ESC (0x1B
) than dump the following characters in a string until you find the final delimiter of the ESC sequence (in your case 'n'
). After that you may use sscanf(esqString, formatString, ...)
.
But before you encounter the loop you need to change with termios to raw mode (look at the code example below). Else nothing would be different.
Your program is working but is waiting for an EOL character.
scanf
is line oriented so it waits for a new line before processing. Try running your program and then hit the enter key.
The solution is to use something else that doesn't need a new line to read the input and then use sscanf to parse the values out.
You will also need to make stdin non-blocking or you won't get the input until the buffer is full or stdin is closed. See this question Making stdin non-blocking
You should also call fflush(stdout);
after your printf to ensure it is actually written (printf is often line buffered so without a newline it may not flush the buffer).