I have a chat client that takes in input in raw terminal mode, but I don't know about handling input in this mode. I need to know 2 things:
\n
?Also, an example character-by-character read loop that flushes on \n
would be really great to see. Thanks!
In Windows there is a very useful function kbhit() but that is not there in linux unfortunately. There can be multiple methods for this. we'll make our own kbhit() method for linux. kbhit() will return non zero value when something is detected in the input buffer otherwise it will return 0 and pass on. In simple words it is non-blocking. Whenever the result is true then call getch() method to fetch that pressed key.
#include <stdio.h>
#include <termios.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/time.h>
void changemode(int);
int kbhit(void);
int main(void)
{
int ch;
changemode(1);
while ( !kbhit() ); // Waiting for some keyboard input.
// something has been detected. now get that.
ch = getchar();
printf("\nGot %c\n", ch);
changemode(0);
return 0;
}
void changemode(int dir)
{
static struct termios oldt, newt;
if ( dir == 1 )
{
tcgetattr( STDIN_FILENO, &oldt);
newt = oldt;
newt.c_lflag &= ~( ICANON | ECHO );
tcsetattr( STDIN_FILENO, TCSANOW, &newt);
}
else
tcsetattr( STDIN_FILENO, TCSANOW, &oldt);
}
int kbhit (void)
{
struct timeval tv;
fd_set rdfs;
tv.tv_sec = 0;
tv.tv_usec = 0;
FD_ZERO(&rdfs);
FD_SET (STDIN_FILENO, &rdfs);
select(STDIN_FILENO+1, &rdfs, NULL, NULL, &tv);
return FD_ISSET(STDIN_FILENO, &rdfs);
}
I recommend the GNU readline library for this. It takes care of the tedious work of getting lines of input, and allows the user to edit his line with backspace, left and right arrows, etc, and to recall older command using the up arrow and even search for older command using ^R, etc. Readline comes installed with typical unix-like distributions like linux, but if you don't have it, you can find it here
Edit: Here is a minimal readline example:
#include <stdio.h>
#include <readline/readline.h>
#include <readline/history.h>
int main(int argc, char ** argv)
{
while(1)
{
char * line = readline("> ");
if(!line) break;
if(*line) add_history(line);
/* Do something with the line here */
}
}
Compile with gcc -o test test.c -lreadline -lncurses.
If you can't use readline, getline is an alternative:
#include <stdio.h>
int main()
{
char * line = NULL;
size_t len;
while(getline(&line, &len, stdin) >= 0)
printf("I got: %s", line);
}
If even getline is unacceptable, you can use fgets. It will not dynamically allocate a buffer of suitable size, so too long lines will be truncated. But at least it is standard C:
#include <stdio.h>
int main()
{
char buf[1000];
while(fgets(buf, sizeof(buf), stdin)
printf("I got: %s, line);
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With