How can I execute a command when user press a key in a command-line C application? Is it possible when window isn't focused
Depends on the program itself, you could do either of those:
block on unbuffered getc you get the key strokes as they come and not when users hits return.
create some sort of event loop, using select/epoll or event framework like (libevent/libev) and get a callback whenever a user hits a key.
use a toolkit like ncurses which provides a pseudo graphical command line interface and an event loop.
if the keys you're interesting in capturing are things like CTRL+C, you need signal handlers.
Related
Using a Linux OS, I need to transparently pass all keystrokes from remote connections to local hardware connections. This is fairly straight forward for everything but signals. I know I can register handlers for each signal that capture and pass the keystroke, but this seems like a hack that might not work for edge cases (what if someone changes the interrupt key combo mapping, would I be double passing the keystrokes, etc.).
In order to come up with a better solution, I really need to know more about how the key combos, IE: CTRL-C, become signals, IE: SIGINT.
How does the keycombo become a Signal (in the kernel, client application, runtime)?
Is the keystroke still passed? If CTRL-C has a null handler, does STDIN still get CTRL-C?
What is the best way to not interpret any keystroke as a signal combination? Can this be done in TTY or Environment settings?
The key combo is turned into a signal by the terminal's line discipline, a layer in the TTY subsystem. Here's the description from Wikipedia:
For example, the standard line discipline processes the data it receives from the hardware driver and from applications writing to the device according to the requirements of a terminal on a Unix-like system. On input, it handles special characters such as the interrupt character (typically Control-C) and the erase and kill characters (typically backspace or delete, and Control-U, respectively) and, on output, it replaces all the LF characters with a CR/LF sequence.
The keypress is not passed, it's suppressed when the signal is raised. If the process has no SIGINT handler, the kernel will terminate it.
You can obviously override this: that's how tools like ssh work. You can easily do this by setting the terminal to "raw" mode, e.g. with the shell command stty raw. If you then run cat -vE you can hit any keys you want and see them printed in caret notation. Make sure to plan on a way to close the terminal because you can obviously not Ctrl-C/Z/D out of it anymore.
How does the keycombo become a Signal (in the kernel, client application, runtime)?
This translation is performed as part of the kernel's TTY line discipline. There are a number of other translations performed as part of this process, like end-of-file (^D), stop signalling (^Z), character echo, basic line editing (backspace, ^U, etc), and DEL/BS and CR/CRLF translation.
Is the keystroke still passed? If CTRL-C has a null handler, does STDIN still get CTRL-C?
No. Control characters which are handled by the line discipline are not passed to the foreground process.
What is the best way to not interpret any keystroke as a signal combination? Can this be done in TTY or Environment settings?
Use tcgetattr() and tcsetattr() to change the terminal attributes. The c_cc element of struct termios contains settings for control characters; you can disable some or all elements by setting them to _POSIX_VDISABLE.
(You can also use cfmakeraw() -- documented at the same page as above -- to clear most elements of a struct termios, giving you a mostly "raw" terminal. However, this may disable more terminal behaviors than you expect.)
I have implemented my own shell which executes all existing UNIX commands and several custom commands. What I need to do is, to access previous commands by using arrow up/down keys in the way exactly how UNIX terminal does.
I have found that I could use getch() method of <curses.h> library. Even if I couldn't figure out how to use that method to expect non-blocking keyboard input, the real problem with that is that I need to compile the program to be able use it as following: gcc myShell.c -lcurses
What I have to do is probably using a signal to listen background input without expecting Enter input. I have also tried to fork() to create another process which will be responsible of waiting arrow keys inputs and then used getch() method to be able to catch the key but it didn't work either.
Since I already use read() method to read the command line inserted by the user. This arrow key input should be completely independent from the existing input reading.
Some answers in Stackoverflow points the <conio.h> library which does not exist in UNIX, hence unfortunately platform dependent.
To summarize briefly, I need to read arrow up/down keys in the background in my own shell and I have to do that platform independent and without being have to type something other than gcc myShell.c for compilation. It also should be captured without Enter press.
If any details about my question is not clear enough, please let me know to explain with more details as I could.
Thanks in advance!
The problem here is with the terminal you're using, not your program. For example, Windows command prompt will buffer input before even sending it to your program, so there is no platform-independent way to force the terminal to give you that data. I suspect curses has a platform-dependent way to turn off that buffering, and thus can get the character.
See answers to this question for more details: How to avoid press enter with any getchar()
I'm trying to call a function when a user presses a key, somewhat like sending a signal with Ctrl-C. The idea is to be doing something, say in a while loop, and actively listen for, say, the 'f' key being pressed. When it is pressed, the program will stop performing the loop and do something else because the 'f' key was pressed.
Is there a way to customize the signal mapping? I didn't have much luck with this. There also seemed to be 1 or 2 available signals for customization, but I need 3.
If I use getchar(), the user needs to press the 'f' key AND THEN press the enter key. I would like for them to just press the 'f' key and not have to press the enter key.
It is very similar to using unix's more program where the user can just press the space bar to go through pages.
Any help is greatly appreciated!
If for some reason you do not like ncurses, you can try something like the following.
You can use a separate thread which uses select() on stdin then performs a read() on stdin and parses user input; if the key is what you are looking for, send a signal (i.e. USER1 or USER2 are unused) to your main thread. In your signal handler, perform whatever operation you are looking to do on the interrupt. Note that doing this means that your code must be interruptible so the interrupt does not break your computation.
By far the simplest option is to use ncurses.
However, if that's not acceptable, POSIX (and therefore Linux too) defines a series of routines for 'terminal control' — the names start with tc and include:
tcdrain()
tcflow()
tcflush()
tcgetattr()
tcgetpgrp()
tcgetsid()
tcsendbreak()
tcsetattr()
tcsetpgrp()
In this context, you primarily need tcgetattr() and tcsetattr(). You will need to study the strictures in the definitions for tcgetattr() and tcsetattr(), and will need to study the structures and flags in the <termios.h> header. Look at the ICANON local mode, for example: you will probably want to turn that off so that characters are available to read as soon as they are typed.
I am trying to implement a simple shell in linux and one of the features it should have is to enable to user to press <ctrl+D> and make it stop whatever it is doing - Basicly exactly what <ctrl+C> does in Bash.
Now I was wondering on the easiest way to do this, and I was thinking of some kind of key listener which would make the current task stop. Now the only way I could think of doing this would be to have a separate thread which would force stop and return the main thread to the base state, where it can take new input.
A separate thread would be the only way to "constantly" listen for the correct keypress.
I was hoping for some thoughts on this and possibly a better way to go about it.
[Edit]
I am trying to make a simple shell which can execute external programs, print/change directory, print/set path, print command history, invoke commands from history and print/set/remove command aliases. The CTRL-D is meant to be the equivalent of the CTRL-C in Bash, which allows the user to immediately exit a currently running program, not to exit the shell itself. [/Edit]
Why don't you just handle Ctrl-C?
Here is just one of many SO disussions on trapping the signal: Catch Ctrl-C in C
Ctrl-D generally represents EOF on standard input. You shouldn't mess with it.
If you want the Control-D character to generate an interrupt for you, then:
You need to map the EOF character to something other than Control-D.
You need to map the interrupt character to Control-D.
You do this in POSIX with the <termios.h> header and the functions:
tcgetattr()
tcsetattr()
You'd retrieve the current attributes in a struct termios using tcgetattr(). You'd make a copy of the structure, and modify (for sake of argument) the copy, changing the elements of the c_cc array indexed by VINTR and VEOF (plus any other changes you want to make), and then setting the new attributes using tcsetattr(). You'd also arrange to ensure that you restore the original terminal settings (by another call to tcsetattr() using the original set of attributes retrieved with tcgetattr()) before your shell exits. This might be done by a handler registered with atexit(), or by other mechanisms. You should endeavour to reset the terminal attributes under all circumstances. You can't do anything about a SIGKILL killing you.
While you're testing this, make a little script for yourself:
echo stty $(stty -g) > sane
chmod u+x sane
That records the current (presumably sane) terminal settings in a form that is designed for stty to read reliably. If (when) you have problems with your shell, you can use Control-JsaneControl-J to run the script and reset your terminal back to the known sane settings. This is also useful if you're developing programs that use the curses library.
Unless my comment on the other answer is incorrect, I think what you should do is:
if (!fgets(input, sizeof(input), stdin) == NULL)
{
... do cleanup here ...
exit(0);
}
or something equivalent to that.
One programming construct I use quite a bit in LabVIEW is the Event Structure. This gives me the benefit of not having to needlessly waste CPU cycles via polling but only perform actions when an event I'm interested in is generated.
As an experienced LabVIEW programmer with a decent understanding of C, I'm curious how one would go about emulating LabVIEW's event structure in C; preferably under Linux. A small code sample (like the one in the link above) illustrating how this might be done would be much appreciated. Also, if there already exists 3rd party libraries (for Linux) to add this event framework to C, that would be nice to know as well. Thanks.
The Event Structure is really just an abstraction that hides the thread of execution from you. There has to be some code running somewhere on the computer that is checking for these events and then calling your event handlers. in C, you'd be expected to provide this code (the "main loop" of the program) yourself. This code would check the various event sources you are interested in and call your event handler functions.
The trick then becomes how to not have this main loop wildly spinning the CPU. One easy trick is to have the main loop sleep for a period of time and then check if any events need to be handled, and then sleep again. This has the downside of introducing latency. A better trick, when applicable, is to have the Operating System do these checks as part of its normal operations, and then wake your application's main loop up when something interesting happened. In Linux, this is done with the 'select' system call, but select has the limitation that it can only specify a resource that can be associated with a file descriptor, so devices, stdin, files, network ports are fine.
Edit: To clarify for my downvoters: I am not denying the existance of hardware interrupts. Yes, in cases where code has direct access to hardware interrupts for all events that it wishes to handle (such as an embedded system or device driver) you can write truly "event driven" code with multiple entry points that does not busy wait or sleep. However, in a normal application level C program running under Linux, this code architecture does not literally exist but is emulated at the application level. Any Linux application is going to have a main loop, and at least one thread of execution. This thread may get paused by the scheduler, but it always exists and always has an instruction pointer at a particular instruction. If the code leaves the main() the program ends. There is no facility for the code to return from main and get a callback later on from the kernel. The code has a single entry point and must call its various event handlers manually. Other than in a device driver (or very specific system code using signals), you can not have the kernel or hardware automatically call a certain function if the user clicked on a certain menu item, instead your code is running, detects this event itself, and calls the correct event handler.
You can tell LabView "Call this function when XX happens". In C, you tell your own event dispatch code "Call this function when XX happens".
What I'm trying to say (poorly?) is that the Event framework architecture is not native to a C / Linux application. It must be emulated by your code by having a main dispatch thread that gives the appearance of an event driven framework. Either you do this manually, or use an event library that does this behind the scenes to give the appearance of an event driven model. LabView takes the second approach, so it appears that no code is running when no events are happening, but in reality there is LabView's own C++ code running managing the event queues. This doesn't mean that it is busy waiting all the time, as I said before there are system calls such as select and sleep that the code can use to yield cpu time when it has no work to do, but the code can not simply stop executing.
Lets say you want to write an "event driven" program with two event handlers. One that gets called every ten seconds called tick() and one that gets called every time a key gets pressed called key(), and one that gets called everytime the word "foobar" gets typed called foobar(). You can define these three event handlers, but in addition you need some dispatch main thread that basically does
while not quitting
If 10 seconds have elapsed, call tick()
If Key has been Pressed
call key()
add save the key to our key buffer
If buffer now contains "foobar" call foobar() and clear buffer
Wait()
If all of the events you care about are system level events or time level events, you can Wait() can simply be telling the kernel 'wake me up when one of these things happens' so I don't need to 'busy wait', But you can't simply tell the Kernel "call foobar() when "foobar is pressed". You have to have application level dispatch code that emulates the Event Structure. You're C program only has a single entry point from the kernel for each thread of execution. If you look at libraries that provide event dispatch models, such as Qt, you will find that they are working like this under the hood.
I like libev for this sort of thing.
Most GUI toolkits (GTK, Qt, etc.) implement their own abstraction of an event loop. I've pastebinned a sample program here, because it was a bit long to include in the answer. It's a port of the LabVIEW example you mentioned to C using the GTK toolkit, because that's the one I'm familiar with. The basics of the event loop are not much different in other toolkits, though.
If all you care about is keyboard input, C standard I/O is what you want. By default input streams are buffered and will stall your program until input is received. Use scanf, getchar, whatever else in <stdio.h>.
If you want mouse input, you'll need to be more specific about your platform as C/C++ has no native support for the mouse or windows.
A good analogy to LabVIEWs event structure is Win32's "event pull" function GetMessage(). GetMessage() waits forever until a GUI event occurs. There are much more events, even for every child window (LabVIEW: control or indicator) in Windows than in LabVIEW. GetMessage() simply returns on every event, fine filtering (as in LabVIEW) has to be done later, typically using DispatchMessage() and the Window's event handler procedure WindowProc() with its more or less large switch() statement.
Most tookits use "event push" style which is not adaequate to the event structure. Interrupt driven programs too.
If a timeout is used, think that MsgWaitForMultipleObjects() with zero file handles is called before PeekMessage(). The timeout case applies when no event arrived in the given time span.
Actually, LabVIEWs event structure should be inside a separate loop. A separate loop is a thread. For typical Win32 programming, GetMessage() is used in the main thread, and additional ("worker") threads are generated by user interaction as needed.
LabVIEW cannot easily create a thread. It is only possible by invoking an asynchronous SubVI. Really! Therefore, most LabVIEW programs use a second while loop as a permanently available worker thread that will run when something has to be done and block (i.e. stop consuming CPU power) otherwise. To instruct what has to be done in background, a queue is used.
As a bad side effect, when the worker thread does something, the user cannot do something else in background as there is only one worker thread.
The LabVIEWs event structure has a big difference to other programming languages: LabVIEW events can have multiple consumers! If multiple event structures are used, everything continues to work well (except for events with boolean return values). In Windows, events are posted to a specific thread, mostly to a Windows' thread. To feed multiple threads, events have to be posted multiple times. Similar to other programming languages. Events there are handled by something similar to LabVIEWs “Queue” related functions: If someone receives the event, it is out off the queue.
Multiple-targetting require that every consumer registers itself somehow to the producer. For GUI events, this is done automatically. For user events, this must be done programmatically. See LabVIEW examples.
Distributing events to multiple listeners is realized in Windows using DDE but that's merely for processes than for threads. Registering to a thread is done using DdeConnect() or similar, and events are pushed to a callback function. (To be more exact how Win32 works, GetMessage() receives DDE messages, and DispathcMessage() actually calls the callback function.)