I am writing a shell emulator in C, and put the terminal in raw mode. To get the cursor position and move using termcaps when necessary, I printed the escape sequence \033[6n
and parsed its return.
The problem is that a high input rate (when I basically hit my keyboard), my input messes up with getting the return of the escape sequence, and ;
characters appear on my screen.
This is how I parsed the return of the escape sequence :
static int fillup_cursor_position(int *x, int *y)
{
int result;
result = 0;
if ((result = read_cursor()) != 27)
return 0;
if ((result = read_cursor()) != '[')
return 0;
result = read_cursor();
while (result >= '0' && result <= '9')
{
*y = 10 * *y + result - '0';
result = read_cursor();
}
if (result != ';')
return (0);
result = read_cursor();
while (result >= '0' && result <= '9')
{
*x = 10 * *x + result - '0';
result = read_cursor();
}
if (result != 'R')
return 0;
return 1;
}
This is the function read_cursor I called several times :
static int read_cursor(void)
{
char buffer[4];
int n;
n = 0;
while (1)
{
n = read(0, &buffer, 1);
if (n > 0)
return buffer[0];
else
return 0;
}
}
And finally this is how I began by setting the terminal and raw-mode to have a non-blocking read() :
static int set_non_canonical_input(void)
{
struct termios termios_cpy;
if (tcgetattr(0, &termios_cpy) != 0)
return 0;
cfsetispeed(&termios_cpy, B50);
cfsetospeed(&termios_cpy, B50);
termios_cpy.c_cc[VMIN] = 1;
termios_cpy.c_cc[VTIME] = 0;
termios_cpy.c_lflag &= (IGNBRK);
termios_cpy.c_lflag &= (ICANON);
if (tcsetattr(0, TCSANOW, &termios_cpy) != 0)
return 0;
return 1;
}
I tried separating those two inputs by writing on the file stream, or by trying to lock the file access with fcntl()
, or by modifying the baud rate, all to no avail.
I'm sure there is an easy way to do this and that I am confused somewhere, but I can't seem to find.