Cómo leer el búfer de entrada del terminal inmediatamente después de presionar una tecla

Quiero leer las pulsaciones de teclas de flecha en mi programa c y reemplazarlas (inmediatamente en el terminal) por alguna otra cadena. Estoy tratando de implementar la funcionalidad del historial de bash como en las terminales unix. Escribí este código.

int
main(int argc, char *argv[])
{
    char c;
    char str[1024];
    int i = 0;
    while((c = fgetc(stdin)) != '\n'){
      if(((int)c) == 27){
        c=fgetc(stdin);
        c=fgetc(stdin);
        if (c == 'A')
        {
          printf("%c[A%c[2K",27, 27);
          printf("UP");
        }
      }
      str[i++] = c;
    }
    printf("\n");

  return 0;
}

Pero esto no funciona porque los terminales esperan una nueva línea o EOF para enviar el búfer de entrada a stdin. Entonces, tengo que presionar la tecla enter / return para analizar la entrada del usuario.

Aqui en estoresponder el usuario mencionó usarsystem ("/bin/stty raw"); pero esto reemplaza todos los comportamientos predeterminados del terminal (por ejemplo, retroceso, eliminación, etc.).

Entonces, ¿hay alguna manera de que pueda leer / manipular el búfer de entrada de los terminales directamente y ajustar el búfer en sí mismo si se detecta la pulsación de la tecla de flecha?

Entorno - Ubuntu (Linux)

Actualización 1: ¿Existe algún método para cambiar la señal / interrupción (el valor predeterminado es presionar la tecla Intro) que hace que el terminal envíe la entrada almacenada al búfer? Esto también puede ayudarme a lograr el mismo comportamiento.

Código final:

Descubrí los caracteres ASCII para pulsaciones de teclas específicas comprobando la salida destrace bash

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <termios.h>

#define ESCAPE '\33'
#define BACKSPACE '\177'
#define DELETE '~'

int main(){
    struct termios termios_p;
    struct termios termios_save;
    tcgetattr(0, &termios_p);
    termios_save = termios_p;

    termios_p.c_lflag &= ~(ICANON|ECHO);
    tcsetattr(0,TCSANOW, &termios_p);
    char buff;
    while(read(0, &buff, 1) >= 0){
        if(buff > 0){
            if(buff == ESCAPE){
                read(0, &buff, 1);
                read(0, &buff, 1);
                if(buff == 'A'){
                    write(2, "up", 2);
                }else if(buff == 'B'){
                    write(2, "down", 4);

                }else if(buff == 'C'){
                    write(2, "\33[C", 3);

                }else if(buff == 'D'){
                    write(2, "\10", 2);                    
                }
            }else if(buff == BACKSPACE){
                write(2, "\10\33[1P", 5);
            }else if(buff == DELETE){
                write(2, "\33[1P", 4);
            }else{
                write(2,&buff,1);
            }
            // write(2,&buff,1);
            if(buff == 'q'){
                break;
            }
        }
    }
    tcsetattr(0,TCSANOW, &termios_save);
    return 0;
}

Respuestas a la pregunta(2)

Su respuesta a la pregunta