I am using a while loop which doesnt terminate, for reproducing Tail command of unix using C code. I need a way to stop the loop apart from Ctrl + C which quits the process i believe. Is there any way to read Keyboard commands when used within the code ? The problem with using getchar() is that it stops the loop from running until a char is entered. Is there any alternative solution to this issue ?
You need to turn off blocking and line buffering. Turn off blocking so getc() returns right away. It will return -1 until it has a real character. Turn off line buffering so the OS sends the char right away instead of buffering it up until it has a full line which occurs when you press return.
#include <unistd.h> /* UNIX standard function definitions */
#include <fcntl.h> /* File control definitions */
#include <termios.h> /* POSIX terminal control definitions */
int main(void) {
// Turn off blocking
fcntl(STDIN_FILENO, F_SETFL, O_NONBLOCK);
struct termios options, oldoptions;
tcgetattr(STDIN_FILENO, &options);
// Disable line buffering
options.c_lflag &= ~( ICANON);
// Set the new options for the port...
tcsetattr(STDIN_FILENO, TCSANOW, &options);
while(1) {
char c = getc(stdin);
if(c != -1) break;
}
// Make sure you restore the options otherwise you terminal will be messed up when you exit
tcsetattr(STDIN_FILENO, TCSANOW, &oldoptions);
return 0;
}
I agree with the other posters that you should use signals, but this is the answer to what you asked.
This sounds very much like this question from the comp.lang.c FAQ.
Q: How can I read a single character from the keyboard without waiting for the RETURN key? How can I stop characters from being echoed on the screen as they're typed?
Related
I'm writing a menu driven program with a switch statement and while loop. My prof wants us to include "Press any key to continue..." and says to use getchar() for this. He says we will lose points if it requires us to press enter, which is what happens for me when I use the getchar().
I have seen many posts about using getch() with , however this is not working because I am using a C program compiled and executed with cygwin.
Thanks in advance
EDIT
Updating since I have not seen any answer for this specific question using Unix/Linux...
Emailed my prof and he got back to me with this...
"Unix/Linux issues. The keyboard input/output is buffered, i.e., your program might not get the character immediately after a user presses a key. Usually, the Operating System (OS) will send characters pressed after an ENTER key is pressed. If you want your program to get the character immediately after the user pressed it, run the following command in your shell (command window or Terminal). You only need to run it once after you first open your shell
stty -icanon min 1
I did this command in the shell before compiling and it still didn't work.
I then used getchar(); twice in a row since a scanf was used previously and doesn't consume the enter used and passes it to the first getchar();
Now it works and I can press ANY key to continue...
For Linux I use the following code.
#include <stdio.h>
#include <termios.h>
#include <unistd.h>
int getch (void)
{
// Declare variables.
int c = {0};
struct termios oldt = {0};
struct termios newt = {0};
// Get terminal attributes.
tcgetattr(STDIN_FILENO, &oldt);
// Store attributes.
newt = oldt;
// Set terminal to non-buffered.
newt.c_lflag &= ~(ICANON | ECHO);
tcsetattr(STDIN_FILENO, TCSANOW, &newt);
// Get user input.
c = getchar();
// Reset terminal attributes.
tcsetattr(STDIN_FILENO, TCSANOW, &oldt);
// Return character.
return(c);
}
For Windoze, just use #include <conio.h>.
I am trying to detect any character typed to stdin (without a newline character).
I tried :
setvbuf(stdin, NULL, _IONBF); //This returns 0
struct pollfd pfd = {STDIN_FILENO, POLLIN};
while (!poll(pfd, 1, ms)) {
/* do some thing, e.g. printf("n\n"); */
}
It appears not stop printing when I typed q, but did stop after I hit enter. The system I am working on is arch-linux, compiler is gcc.
This works for me but it may depend on your system/terminal
#include <stdio.h>
#include <sys/ioctl.h>
#include <termios.h>
#include <unistd.h>
int main() {
int i = 0;
struct termios ts;
tcgetattr(0, &ts);
ts.c_lflag &= ~ICANON;
tcsetattr(0, TCSANOW, &ts);
while (!ioctl(0, FIONREAD, &i) && !i) {
printf("x");
fflush(stdout);
sync();
usleep(100);
}
printf("\n");
return 0;
}
Craig really answered this for you. I was just curious enough to find an implementation. The ioctl(0, FIONREAD, &i) gets the number of characters in the buffer and puts it into i. The man pages for termios and ioctl_tty contained all of the details needed to come up with this solution.
Honestly, though, if you are wanting to make something interactive like this, ncurses makes it somewhat simpler.
The q is being held up in the kernel's TTY layer driver/buffer because it is in "cooked" mode.
In this mode, it will only return something to the app when the driver sees a newline. It then gives back: q\n (i.e. q<newline>).
To have it return immediately on any character, you'll have to use ioctl calls to put the TTY layer into "raw" mode.
You'll need to use [recommended] the termios calls: tcgetattr and tcsetattr
UPDATE:
Will ioctl alone works? Which command is corresponding to change terminal into raw mode?
Look at man termios. It has full documentation for how to set raw mode (what is called "non-canonical" mode in the man page).
It's been a while since I've done this, but here's a skeleton function.
Although the function restores original state at the end, you might want to set non-canonical mode once at program start.
But, then, you'll have to handle all your own line editing (e.g. supporting backspace, etc.) for other sections of your program that want normal canonical line editing.
#include <termios.h>
#include <unistd.h>
void
change_tty(int fd)
{
struct termios orig;
struct termios raw;
// get original cooked/canonical mode values
tcgetattr(fd,&orig);
// set options for raw mode
raw = orig;
#if 0
raw.c_lflag &= ~ICANON;
raw.c_cc[VMIN] = ...
raw.c_cc[VTIME] = ...
#else
cfmakeraw(&raw);
#endif
// put unit into raw mode ...
tcsetattr(fd,TCSANOW,&raw);
// do stuff in raw mode ...
// restore original mode
tcsetattr(fd,TCSANOW,&orig);
}
Program:
#include<stdio.h>
void main()
{
int time=1800;
while(1){
system("clear");
time-=1;
printf("%d\n",time);
sleep(1);
if(time==0)
pause();
}
}
The above program stops when the time reaches 0. My requirement is during the runtime of the program, If I press any key like spacebar or any other key, the program gets paused and once again I press the key, the program gets resumed. So for doing this, before execution of
while condition, we submit the signal handler for keyboard interrupt. In C how to do this.
What is the function used to get keyboard interrupt. I dont want to get input from the user, I want to handle the interrupt generated by the user through keyboard.
Thanks in Advance..,
You need conio.h for your requirement.It defines kbhit() and getch() both wait for input from keyboard.
Whenever kbhit() is called, it checks the keyboard buffer and returns a nonzero value if the buffer has any keypress otherwise 0 is returned.
The conio.h is used by MSDOS compilers and is not the part of standard C libraries (ISO). It is also not defined in POSIX.
#include<stdio.h>
#include<conio.h>
int main()
{
while(1)
{
while(!kbhit())
{
//works continuously until interrupted by keyboard input.
printf("M Tired. Break Me\n");
}
getch();
}
return 0;
}
For linux you may use the following snippet to implement kbhit() by using fnctl() from fnctl.h for signal handling:
#include <termios.h>
#include <unistd.h>
#include <fcntl.h>
int kbhit(void)
{
struct termios oldt, newt;
int ch;
int oldf;
tcgetattr(STDIN_FILENO, &oldt);
newt = oldt;
newt.c_lflag &= ~(ICANON | ECHO);
tcsetattr(STDIN_FILENO, TCSANOW, &newt);
oldf = fcntl(STDIN_FILENO, F_GETFL, 0);
fcntl(STDIN_FILENO, F_SETFL, oldf | O_NONBLOCK);
ch = getchar();
tcsetattr(STDIN_FILENO, TCSANOW, &oldt);
fcntl(STDIN_FILENO, F_SETFL, oldf);
if(ch != EOF)
{
ungetc(ch, stdin);
return 1;
}
return 0;
}
The keyboard does not exist in purely standard C99 or C11 (stdin is not a keyboard, and could be a pipe(7) so is not always a tty(4); you might read from /dev/tty ...).
So it is much less simple that what you want it to be, and it is operating system specific. I am focusing on Linux.
Read much more about ttys, notably read the tty demystified. Notice that tty are usually in cooked mode, where the kernel is buffering lines (in addition of stdin being line buffered).
The reasonable way is to use a terminal library like ncurses or readline. These libraries are setting the tty in raw mode (which you might do by yourself, see this and termios(3); you'll probably need also to poll(2)). Be sure to exit properly and reset the tty to cooked mode before exiting.
But your life is probably too short to dive into termios(3) and tty_ioctl(4) so just use ncurses or readline
You could also consider some GUI application (e.g. above X11 or Wayland). Then use a toolkit (GTK, Qt, ...).
My requirement is during the runtime of the program, If I press any key like spacebar or any other key, the program gets paused and once again I press the key, the program gets resumed.
You can achieve this with this type of code
#include <stdio.h>
int main()
{
char i;int y=0;
while(1)
{
if(!(_kbhit()))
{
y=0;
printf("//key is not pressed");
//do what you want
}
else
{
printf("key pressed (execution pause) , press again to resume");
i=_getch();
y=1;
}
if(y==1)
{
getch();
}
}
return 0;
}
I have a infinite loop like the following one, and within this loop, I want to continuously check the keyboard to see if the escape key (ESC) has been pressed or not. If it is pressed, then the loop should be broken. How I can do this in C? (I am using gcc, and do access to pthreads as well in case this must be done via threads)
while(1){
//do something
//check for the ESC key
}
This is heavily system dependent. In Unix/Linux systems, the default terminal handler gathers lines and only notifies the program when a full line is available (after Enter is hit.) If you instead want keystrokes immediately, you need to put the terminal into non-canonical mode:
#include <termios.h>
struct termios info;
tcgetattr(0, &info); /* get current terminal attirbutes; 0 is the file descriptor for stdin */
info.c_lflag &= ~ICANON; /* disable canonical mode */
info.c_cc[VMIN] = 1; /* wait until at least one keystroke available */
info.c_cc[VTIME] = 0; /* no timeout */
tcsetattr(0, TCSANOW, &info); /* set immediately */
Once you've done that, you can use any calls that read from stdin and they will return keys without waiting for the end of the line. You can in addition set c_cc[VMIN] = 0 to cause it to not wait for keystrokes at all when you read from stdin.
If, however, you're reading stdin with stdio FILE related calls (getchar, etc), setting VMIN = 0 will make it think you've reached EOF whenever there are no keys available, so you'll have to call clearerr after that happens to try to read more characters. You can use a loop like:
int ch;
while((ch = getchar()) != 27 /* ascii ESC */) {
if (ch < 0) {
if (ferror(stdin)) { /* there was an error... */ }
clearerr(stdin);
/* do other stuff */
} else {
/* some key OTHER than ESC was hit, do something about it? */
}
}
After you're done, you probably want to be sure to set the terminal back into canonical mode, lest other programs (such as your shell) get confused:
tcgetattr(0, &info);
info.c_lflag |= ICANON;
tcsetattr(0, TCSANOW, &info);
There are also other things you can do with tcsetattr -- see then manual page for details. One thing that might suffice for your purposes is setting an alternative EOL character.
If the main job you're doing can be placed within this main loop, you could go for using STDIN in non-blocking mode. You still have a problem with the terminal which does line-buffering normally. You shall put the terminal to raw mode as well.
What about using Ctrl-C (interrupt)?
Non-blocking means that the read() system call always returns immediately even if there are no new bytes in the file. On Linux/Unix you can make STDIN nonblocking this way:
#include <unistd.h>
#include <fcntl.h>
fcntl(0, F_SETFL, O_NONBLOCK); /* 0 is the stdin file decriptor */
This is what you want:
#include <stdio.h>
#include <conio.h>
void main() {
int c;
while((c = getch()) != EOF )
if(c == 27) break;
/* 27 is the ASCII code for Esc */
}
I'm working on a program which will be taking in user input from the console as well as printfing out in a separate thread. I want to avoid situations where the user is halfway through typing something in and a printf comes along and prints itself at the cursor.
Is there a way to do non-blocking io in c from the console window? Ideally, capturing keypresses or something like that such that what the user types doesn't appear on the screen. I'm developing in Ubuntu, and it's best if I don't have to use things like ncurses.
using termios you can disable terminal echoing:
#include <termios.h>
struct termios oflags, nflags;
tcgetattr(fileno(stdin), &oflags);
nflags = oflags;
nflags.c_lflag &= ~ECHO;
nflags.c_lflag |= ECHONL;
if (tcsetattr(fileno(stdin), TCSANOW, &nflags) != 0) {
/* handle error */
}
then before exit (use atexit) you must restore the terminal:
if (tcsetattr(fileno(stdin), TCSANOW, &oflags) != 0) {
/* handle error */
}
Here's an example of how to turn off echo from C, taken directly from an HP forum (and I haven't personally tested it):
Okay this should be a simple example
of turning off echo:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <termios.h>
#define STDIN_FDES 0
struct termios save;
int main(int argc, char *argv[])
{
int cc = 0;
char s_tmp[80],*p = NULL;
struct termios work;
cc = tcgetattr(STDIN_FDES,&save);
work = save;
work.c_lflag &= ~(ECHO);
cc = tcsetattr(STDIN_FDES,TCSANOW,&work);
(void) printf("\nEnter value: ");
(void) fflush(stdout);
p = fgets(s_tmp,sizeof(s_tmp),stdin);
if (p != NULL) (void) printf("Out -> %s\n",p);
cc = tcsetattr(STDIN_FDES,TCSANOW,&save);
return(cc);
}
NOTE: It is very important that you
have signal handlers to catch SIGINT,
SIGTERM, ... and reset the terminal
using the original termios because the
last tcsetattr() wins and this applies
to the terminal device NOT simply the
process. If you leave the process with
echo off, it will be off in the shell
as well.
Otherwise, if Bash is a suitable approach, apparently you can just do stty -echo.
Turning off echo or using non-blocking I/O isn't the answer, if I understand your question correctly. Rather, you want to prevent a background thread from interrupting a user input thread, right?
For that, you'll need access to raw keypresses instead of line-buffered input. I don't know why you're allergic to ncurses or similar libraries; that's what they're for! I guess you could do it with termios or ioctl calls, if that's how you roll....
But to solve your multi-threaded TTY output problem, you could do this:
1) Create a mutex to control who can access the console
In the background thread, to output a message:
Grab the mutex; write the message; release the mutex; go back to sleep!
In the user input thread:
Grab the mutex when new input is detected. Keep exclusive access until the user hits enter,
then release the mutex and give the background thread a chance to talk.
Does that help?