not 100% sure of what you are after, below, a trivial example to capture each char as entered plus catch a couple of signals .... if this is not what you are after (or could form the basis of ... ), please elaborate, also - share what you have tried - regardless of any shortcomings !
//
//use(d) https://www.man7.org/linux/man-pages/man3/termios.3.html as reference
//
#include <termios.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
struct termios currentSettings;
void resetSTDIN(struct termios *currentSettings) {
tcsetattr(STDIN_FILENO, TCSAFLUSH, currentSettings); // reset to original settings
}
void setSTDIN(struct termios *currentSettings) {
struct termios updatedSettings;
tcgetattr(STDIN_FILENO, currentSettings); // get current settings
updatedSettings = *currentSettings; // use those as basis for new settings
updatedSettings.c_lflag &= ~ICANON; // unset 'normal' aka canonical mode, add '|ECHO' if you don't want to see input
updatedSettings.c_cc[VTIME] = 0; // VTIME Timeout in deciseconds for noncanonical read (TIME) 0 == no timeout
updatedSettings.c_cc[VMIN] = 1; // VMIN Minimum number of characters for noncanonical read (MIN).
tcsetattr(STDIN_FILENO, TCSAFLUSH, &updatedSettings);
}
void catchSignals(int sig) {
resetSTDIN(¤tSettings);
exit(1);
}
int main() {
setSTDIN(¤tSettings);
signal(SIGINT|SIGQUIT, catchSignals); // trap ^C, ^\ amend as reqd
printf("[q|Q|^C|^D]' to exit):\n");
char c;
const char ctrlD=4;
while ( read(STDIN_FILENO, &c, 1) == 1 ) {
if ( c == ctrlD || c == 'q' || c == 'Q' )
break;
//printf("%c", c); // if ECHO masked and you want to see the output ...
}
resetSTDIN(¤tSettings);
return 0;
}