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?
Related
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);
}
I am basically a beginner C++ programmer...and it's my first attempt to code in C.
I am trying to program a snake game (using system ("cls")).
In this program I need to get a character as an input (basically to let the user change the direction of movement of snake)... and if the use doesn't input any character within half a second then this character input command needs to be aborted and my remaining code should get executed.
Please give suggestions to sort out this problem.
EDIT: Thanks for the suggestions, but
My main motive of asking this question was to find a method to abort the getchar command even if the user has not entered anything....Any suggestions on this? And by the way my platform is windows
The best way, in my opinion, is using libncurses.
http://tldp.org/HOWTO/NCURSES-Programming-HOWTO/
You have all the tools to make a snake easily.
If you think it's too easy (it is a relatively high level library), look at the termcaps library.
EDIT: So, a non-blocking read with termcaps is :
#include <termios.h>
#include <unistd.h>
#include <term.h>
uintmax_t getchar()
{
uintmax_t key = 0;
read(0, &key, sizeof(key));
return key;
}
int main(int ac, char **av, char **env)
{
char *name_term;
struct termios term;
if ((name_term = getenv("TERM")) == NULL) // looking for name of term
return (-1);
if (tgetent(NULL, &name_term) == ERR) // get possibilities of term
return (-1);
term.c_lflag &= ~(ICANON | ECHO);
term.c_cc[VMIN] = 0; term.c_cc[VTIME] = 0; // non-blocking read
if (tcgetattr(0, term) == -1) // applying modifications.
return (-1);
/* Your code here with getchar() */
term.c_lflag &= (ICANON | ECHO);
if (tcgetattr(0, term) == -1) // applying modifications.
return (-1);
return (0);
}
EDIT 2:
You have to compile with
-lncurses
option.
The way to do this on a UNIX-like platform (such as Linux) is to use the select function. You can find its documentation online. I'm not sure if this function is available on Windows; you didn't specify an operating system.
I got the best suited answer to my question in comments, which was posted by #eryksun.
The best way is to use a function kbhit() (part of conio.h).
You can spawn a new thread that can emulate pressing of the Enter Key after 30 seconds.
#include <windows.h>
#include <stdio.h>
#pragma comment(lib, "User32.lib")
void ThreadProc()
{
// Sleep for 30 seconds
Sleep(30*1000);
// Press and release enter key
keybd_event(VK_RETURN, 0x9C, 0, 0);
keybd_event(VK_RETURN, 0x9C, KEYEVENTF_KEYUP, 0);
}
int main()
{
DWORD dwThreadId;
HANDLE hThread = CreateThread(NULL, 0,(LPTHREAD_START_ROUTINE)ThreadProc, NULL, 0,&dwThreadId);
char key = getchar();
// you are out of getchar now. You can check the 'key' for a value of '10' to see if the thread did it.
// Kill thread before you do getchar again
}
Be careful with this technique, specially if you do geatchar() in a loop, otherwise you might end up with lot of threads pressing ENTER key! Be sure to kill the thread before you start getchar() again.
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 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?
How do you do nonblocking console IO on Linux/OS X in C?
I want to add an example:
#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
int main(int argc, char const *argv[])
{
char buf[20];
fcntl(0, F_SETFL, fcntl(0, F_GETFL) | O_NONBLOCK);
sleep(4);
int numRead = read(0, buf, 4);
if (numRead > 0) {
printf("You said: %s", buf);
}
}
When you run this program you have 4 seconds to provide input to standard in. If no input found, it will not block and will simply return.
2 sample executions:
Korays-MacBook-Pro:~ koraytugay$ ./a.out
fda
You said: fda
Korays-MacBook-Pro:~ koraytugay$ ./a.out
Korays-MacBook-Pro:~ koraytugay$
Like Pete Kirkham, I found cc.byexamples.com, and it worked for me. Go there for a good explanation of the problem, as well as the ncurses version.
My code needed to take an initial command from standard input or a file, then watch for a cancel command while the initial command was processed. My code is C++, but you should be able to use scanf() and the rest where I use the C++ input function getline().
The meat is a function that checks if there is any input available:
#include <unistd.h>
#include <stdio.h>
#include <sys/select.h>
// cc.byexamples.com calls this int kbhit(), to mirror the Windows console
// function of the same name. Otherwise, the code is the same.
bool inputAvailable()
{
struct timeval tv;
fd_set fds;
tv.tv_sec = 0;
tv.tv_usec = 0;
FD_ZERO(&fds);
FD_SET(STDIN_FILENO, &fds);
select(STDIN_FILENO+1, &fds, NULL, NULL, &tv);
return (FD_ISSET(0, &fds));
}
This has to be called before any stdin input function When I used std::cin before using this function, it never returned true again. For example, main() has a loop that looks like this:
int main(int argc, char* argv[])
{
std::string initialCommand;
if (argc > 1) {
// Code to get the initial command from a file
} else {
while (!inputAvailable()) {
std::cout << "Waiting for input (Ctrl-C to cancel)..." << std::endl;
sleep(1);
}
std::getline(std::cin, initialCommand);
}
// Start a thread class instance 'jobThread' to run the command
// Start a thread class instance 'inputThread' to look for further commands
return 0;
}
In the input thread, new commands were added to a queue, which was periodically processed by the jobThread. The inputThread looked a little like this:
THREAD_RETURN inputThread()
{
while( !cancelled() ) {
if (inputAvailable()) {
std::string nextCommand;
getline(std::cin, nextCommand);
commandQueue.lock();
commandQueue.add(nextCommand);
commandQueue.unlock();
} else {
sleep(1);
}
}
return 0;
}
This function probably could have been in main(), but I'm working with an existing codebase, not against it.
For my system, there was no input available until a newline was sent, which was just what I wanted. If you want to read every character when typed, you need to turn off "canonical mode" on stdin. cc.byexamples.com has some suggestions which I haven't tried, but the rest worked, so it should work.
You don't, really. The TTY (console) is a pretty limited device, and you pretty much don't do non-blocking I/O. What you do when you see something that looks like non-blocking I/O, say in a curses/ncurses application, is called raw I/O. In raw I/O, there's no interpretation of the characters, no erase processing etc. Instead, you need to write your own code that checks for data while doing other things.
In modern C programs, you can simplify this another way, by putting the console I/O into a thread or lightweight process. Then the I/O can go on in the usual blocking fashion, but the data can be inserted into a queue to be processed on another thread.
Update
Here's a curses tutorial that covers it more.
I bookmarked "Non-blocking user input in loop without ncurses" earlier this month when I thought I might need non-blocking, non-buffered console input, but I didn't, so can't vouch for whether it works or not. For my use, I didn't care that it didn't get input until the user hit enter, so just used aio to read stdin.
Here's a related question using C++ -- Cross-platform (linux/Win32) nonblocking C++ IO on stdin/stdout/stderr
Another alternative to using ncurses or threads is to use GNU Readline, specifically the part of it that allows you to register callback functions. The pattern is then:
Use select() on STDIN (among any other descriptors)
When select() tells you that STDIN is ready to read from, call readline's rl_callback_read_char()
If the user has entered a complete line, rl_callback_read_char will call your callback. Otherwise it will return immediately and your other code can continue.
Let`s see how it done in one of Linux utilites. For example, perf/builtin-top.c sources (simplified):
static void *display_thread(void *arg)
{
struct pollfd stdin_poll = { .fd = 0, .events = POLLIN };
struct termios save;
set_term_quiet_input(&save);
while (!done) {
switch (poll(&stdin_poll, 1, delay_msecs)) {
...
}
}
tcsetattr(0, TCSAFLUSH, &save);
}
So, if you want to check if any data available, you can use poll() or select() like this:
#include <sys/poll.h>
...
struct pollfd pfd = { .fd = 0, .events = POLLIN };
while (...) {
if (poll(&pfd, 1, 0)>0) {
// data available, read it
}
...
}
In this case you will receive events not on each key, but on whole line, after [RETURN] key is pressed. It's because terminal operates in canonical mode (input stream is buffered, and buffer flushes when [RETURN] pressed):
In canonical input processing mode, terminal input is processed in
lines terminated by newline ('\n'), EOF, or EOL characters. No input
can be read until an entire line has been typed by the user, and the
read function (see Input and Output Primitives) returns at most a
single line of input, no matter how many bytes are requested.
If you want to read characters immediately, you can use noncanonical mode. Use tcsetattr() to switch:
#include <termios.h>
void set_term_quiet_input()
{
struct termios tc;
tcgetattr(0, &tc);
tc.c_lflag &= ~(ICANON | ECHO);
tc.c_cc[VMIN] = 0;
tc.c_cc[VTIME] = 0;
tcsetattr(0, TCSANOW, &tc);
}
Simple programm (link to playground):
#include <stdio.h>
#include <unistd.h>
#include <sys/poll.h>
#include <termios.h>
void set_term_quiet_input()
{
struct termios tc;
tcgetattr(0, &tc);
tc.c_lflag &= ~(ICANON | ECHO);
tc.c_cc[VMIN] = 0;
tc.c_cc[VTIME] = 0;
tcsetattr(0, TCSANOW, &tc);
}
int main() {
struct pollfd pfd = { .fd = 0, .events = POLLIN };
set_term_quiet_input();
while (1) {
if (poll(&pfd, 1, 0)>0) {
int c = getchar();
printf("Key pressed: %c \n", c);
if (c=='q') break;
}
usleep(1000); // Some work
}
}
Not entirely sure what you mean by 'console IO' -- are you reading from STDIN, or is this a console application that reads from some other source?
If you're reading from STDIN, you'll need to skip fread() and use read() and write(), with poll() or select() to keep the calls from blocking. You may be able to disable input buffering, which should cause fread to return an EOF, with setbuf(), but I've never tried it.