Ive been trying to solve this one for some time but im unable to come up with a solution. I need a child process to understand complex WASD keyboard input (with complex I mean detect that both W and A or many other keys are being pressed at the same time) but I think that this is impossible in C due to the way characters are read from the terminal. My parent process only best result (taken from another post) is the following:
int kbhit(){
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(STDIN_FILENO, &fds);
}
int main(){
system("stty raw -echo"); //No need to newline to read key and disables showing pressed key
char command;
unsigned short count = 0;
while(1){
while(1){
if(kbhit()){count = 0; command = getchar(); break;}
if(count > 5) {count = 0; command = 'f'; break;}
count++;
//Add code to somehow wait a few milliseconds
}
//Use read key/command...
//If a certain key is read break out of loop
}
system("stty sane echo"); //Return terminal to normal state
return EXIT_SUCCESS;
}
This is way too "hacky" and it does not detect multiple simultaneous key presses and I need a child process to read these keys, this code does not work under a fork since the keyboard is being sent to the parent, the child has no new STDIN (I think). I cant rewrite my entire program in another language due to many low level things im doing elsewhere. Ive thought of the following solutions but im unsure of which one to go for:
Have the child process use system("xterm") to open a new terminal and send keys over this one, this does not solve the multiple keys same time problem and from my first tests im unable to link this new terminal to the running process as this terminal just runs a fresh bash session. Code blocks until this terminal is closed.
Use another language like c++ or java that does support easily reading simultaneous key presses and somehow "pipe" this to the child process. I guess the child would fork and have the other process run this new code with a system call. Im unsure of how to send this to the other process (sockets maybe?).
Are there other better ways of doing this? Would option 2 work? Im lost and stuck, any help is welcome!
The simplest way to do it will be by creating events.
for example
struct SKeyEvent
{
char key;
uint8_t pressed;
};
so when a key is pressed you can use a callback function to update the structure with the key and 0, 1, 2
1 and 2. 1 = pressed, 2=released and followed right away by 0 = idle.
so when I pressed A the function callback will be called with {key:'A', 1}
if you press W same {'W', 1} so you know that A and W are pressed simultaneously.
when a touch is released you will receive 2 calls for example {'A' : 2}, {'A' :0}
I solved this instead of reading characters from the terminal (does not work since you can only input one char a time...) by reading the actual keyboard device (/dev/...). There are some examples of this around.
The downside is that it captures all keyboard input and you now need to run the program as superuser but it works...
Related
Consider the simple c program :
int main(){
char str[10];
scanf("%s",str);
printf("The string is %s \n",str);
}
According to the book Operating System Concepts a process is in waiting state when it is waiting for some events to occur ( such as an I/O completion or reception of a signal ).
Now as far as I know by the time the process execution reaches the scanf() function the process enters the I/O state (the process stops and is in waiting state). Now it is preempted and another process is executed in the CPU. This system was developed for reasons of efficiency because the CPU shouldn't stay idle when it could execute another process. I totally understand and agree with that. What I don't understand is the exact little time frame within which a process is waiting. Let me explain this more clearly.
Consider the simple program with the scanf() function I just showed here ( let's say it is the process A).
When the process A execution reaches the scanf() function the program expects us to insert something so it stops and we are provided with the window for inserting characters. Is the process A preempted ( CPU is given another process, let's say B) only within the little time interval that extends from when we are asked to insert some value to the exact point in time where the FIRST character input is typed on the keyboard ? Does the cpu resume execution of process A as soon as the FIRST character is typed or does the cpu resume execution of process A only when all the characters are typed and the key enter is pressed to confirm them. Have a look a this picture and tell me which of the two cases are correct or if they are both incorrect. Try also to explain why is that or why isn't like that.
A modern computer would require the enter key be pressed first since it can't return a value only to have you delete it and replace it. However in the first case, process A would have to handle what to do if the backspace key is hit and when it is done reading from input. This is quite awkward, but it can be done.
char *buffer = /* etc. */;
int index = 0;
while(true) {
// We pass responsibility to process B to handle waiting for and returning the next key
// In this case process B is the operating system that handles our IO
char next = osWaitForKeyPress();
// Now that we have an input, process A can handle it before waiting again
if (next == ENTER_KEY) {
// We finished so add null terminator and exit
buffer[index] = '\0';
break;
} else if (next == BACKSPACE_KEY) {
// Move index back by 1 to overwrite previous input
if (index > 0) {
index = index - 1;
}
} else {
// Add character to buffer and increment index
buffer[index] = next;
index = index + 1;
}
}
However in case 2, we just pass all of the responsibility to process B (aka the OS) and let it handle it for us before process A resumes execution.
// Wait until the OS has a full string of input for us.
// During this time we wait on process B.
char *buffer = fgets(stdin);
Hopefully this pseudocode helps clear it up for you.
I haven't found a post addressing a similar scenario so far: In a command-line unix program for sonification of certain floating point data sets, I have a main() which either reads from a file whose name is given as program argumant or stdin redirection ( < ) or data piped from another program ( | ), depending on argc.
For as long as argv[1] is a file name, I can manage gently stopping the execution by hitting 'enter' key, which programmatically sets a condition to fade out the signal, cleanup and regularly exit the audio subroutine and terminate the program. I achieve it by calling a function for non-blocking kbhit(). Definition:
int kbhit(void)
{
struct timeval tv;
fd_set read_fd;
tv.tv_sec = 0;
tv.tv_usec= 0;
FD_ZERO(&read_fd);
FD_SET(0, &read_fd);
if(select(1, &read_fd, NULL, NULL, &tv) == -1)
return 0;
if(FD_ISSET(0, &read_fd))
return 1;
return 0;
}
However, if input is being redirected or piped, kbhit() then prevents from execution by stopping the playback the moment it has started, since it returns 1. I don't know how to deal with it, so I am using SIGINT, which I don't find so elegant. Here are the code snippets:
//... ...
bool stop = false; //global variable
//... ...
if(argc == 1) stdr = true;//flag: reading from redirected or piped stdin (simplified)
//code for reading from file or stdin, using fscanf() ...
//code for initializing and starting audio process ...
//loop, during audio callback on a separate thread ...
while((player.totalFrames < player.totalSize) && !stop){
if(!stdr){ //( = reading from file)
if (kbhit()){
stop = true;
break;
}
}else{ //( = reading from redirected stdin)
if (signal(SIGINT, sig_handler) == SIG_ERR)
printf("\ncan't catch SIGINT\n");
}
}
if(stop){ … }//code for gently fading the signal and stopping the audio process
//cleanup and termination...
//... ...
And here is the standard signal handler which sets stop condition to true:
void sig_handler(int s)
{
if (s == SIGINT){
if(debug)printf("\ncaught SIGINT\n");
stop = true;
}
}
Is there a more elegant way to:
send & catch a message from the keyboard while having input redirected or piped, to allow program cleaning after itself and exiting (other than using SIGINT as described above)?
how would a code allowing for such a message from coputer keyoard (during redirection or piping) look like? Could the arguments inside kbhit() be rearranged somehow, or one has to go in a completely different direction. I have no idea which?
If this is possible, I would kindly appreciate a suggestion. Thanks in advance!
If you want an interactive TTY user to be able to stop a program using an input character (not a signaling character which causes the TTY driver to deliver a signal), and that program must be redirected, then your only resort is to explicitly open a file descriptor to the TTY device (via /dev/tty) and monitor that for input.
Your kbhit function should probably take an int fd parameter, using which you give it the open TTY file descriptor that it should poll.
If you want a single character input from a TTY to be immediately available to the program (even if that character isn't a newline), then you have to put the TTY into "raw mode", or at least partially: at the very least, you have to disable "canonical input processing" via negating the ICANON flag in the c_iflag numeric field in the struct termios structure, and ensure that c_cc[VTIME] and c_cc[VMIN] are set to 0 and 1, respectively. Look up tcgetattr and tcsetattr. You probably want to disable the signaling characters, and disable echoing and other things. Some platforms have a cfmakeraw function which tweaks a struct termios object in the right ways to bring about a very raw mode without having to fiddle with any of the termios flags.
In canonical input processing mode, a TTY won't make input available to the process (and won't select positive under select for input) until a complete line of input is received.
Your problem is that, when reading data from redirection, you're trying to use both the file AND your keyboard. stdin isn't your keyboard anymore, it is the file, and thus you cannot read data from your keyboard (like the "enter" key pressed).
If I'm not mistaken, your only two options are signals and opening a new file descriptor to the keyboard input (the TTY).
I was working on a little program I had to make some time ago, and I wanted to short it up.
This little program was about one thread creating several child who would redirect their standard output/input one to another with pipes in order, except for the last child, who won't redirect it's standard output, like this.
Parent pipe child1 pipe child2 pipe last child
__ __ __
O-----|__|-----O-----|__|-----O-----|__|-----O -> Stdout
First time I face this code, I made a matrix with a dimension of [n_child][2], and made a pipe from every position of that matrix, so it was very easy to connect every pipe to every child when needed. But now I want to try it only with 2 pipes, and "playing" with inheritance.
Maybe I'm not explaining myself really well, so I think everything would be better understood with my code,so here we go.
piping_function(int number_of_child){
int i;
int olddesc[2];
int newdesc[2]; //Here I create the descriptors of the pipes I'll use
int *olddir;
int *newdir;
if(pipe(olddesc)<0 || pipe(newdesc) < 0){ //I create the pipes
//Error
}
olddir = olddesc;
newdir = newdesc; //And attach the directions to the array's direction (we will see later why)
for(i = 0; i < number_of_child; i++){
chaddr[i] = fork();
switch(chaddr[i]){
case -1:
//Error trace
case 0:
dup2(olddesc[0],0); //Here I redirect the pipe who connect the previous child's pipe to the standard input
if(i != number_of_child - 1)
dup2(newdesc[1],1); //And here, except from the last child, I redirect the standard output to the pipe who will connect to the standard input of the next child
close(olddesc[0]);
close(newdesc[1]); //I close the descriptors I don't need
//Several child operations with standard input-output (end up returning 0/1 after the pipeline is connected, so no child will create any child)
default:
if(i == 0)
dup2(olddesc[1], 1); //I want the standard output of the principal proccess only on the first pipe
olddir = newdir; //Here I would want the direction of the "old" pipe to be the direction of the "new" pipe, in order to achieve the pipeline
if(pipe(newdesc)<0)
//Error
break;
}//End of switch
}//End of for
close(olddesc[0]);close(olddesc[1]);close(newdesc[0]);close(newdesc[1]); //I don't need these descriptors anymore, as they must be redirected to the standard's input/output of the process they need.
}//End of function
Well, there is my code. I think I can see the mistake I'm doing, when I make olddir be newdir, and create the pipe, I'm doing olddir to be also that new pipe right? So here comes my question:
Is there any way to achieve that change? I mean, the thing I want is to equal olddir (who is the address of olddesc, right? so if I change that address olddesc's address will be also changed, right?) to newdir, in order to continue with the pipe I created before to redirect the standard output of the "next" child, but I also want newdir to be a NEW pipe.
I don't really know if I explained myself right, I'm not a native speaker and it's a bit difficult to explain these kind of ideas in other language. Feel free to correct any grammar mistake, I'd appreciate it, and to ask any question about the code, as maybe I'm not giving the point I wanted to.
Thanks.
Well, I finally made it, but changing the point of view and not working with any address overwrite, only playing with the iterations, in order always keep the record of one of the two pipes. I didn't really solve the address problem, but it works so, I'm satisfied.
piping_function(int number_of_child){
int i;
int olddesc[2];
int newdesc[2]; //Here I create the descriptors of the pipes I'll use
//Now we'll start from the last pipe, so we can connect the parent to the first one and not connect the last child's output.
for(i = number_of_child - 1; i >= 0; i--){
//Instead of changing addresses, I'll play with the "i"
if(i%2==0){
close(newdesc[0]); //We close the last descriptors
close(newdesc[1]);
pipe(newdesc); //And create a new pipe!
}
else{
close(olddesc[0]);
close(olddesc[1]);
pipe(oldesc);
}
chaddr[i] = fork();
switch(chaddr[i]){
case -1:
//Error trace
case 0:
if(i%2==0){
dup2(newdesc[0],0); //Here I redirect the pipe who connect the previous child's pipe to the standard input
if(i != number_of_child - 1)
dup2(olddesc[1],1); //And here, except from the last child, I redirect the standard output to the pipe who will connect to the standard input of the next child
close(newdesc[1]);
close(olddesc[0]); //I close the descriptors I don't need
}
else{
dup2(olddesc[0],0); //Here I redirect the pipe who connect the previous child's pipe to the standard input
if(i != number_of_child - 1)
dup2(newdesc[1],1); //And here, except from the last child, I redirect the standard output to the pipe who will connect to the standard input of the next child
close(olddesc[1]);
close(newdesc[0]); //I close the descriptors I don't need
}
//Several child operations with standard input-output (end up exiting 0/1 after the pipeline is connected, so no child will create any child)
default:
if(i == 0)
dup2(newdesc[1], 1); //I want the standard output of the principal proccess only on the first pipe
break;
}//End of switch
}//End of for
close(olddesc[0]);close(olddesc[1]);close(newdesc[0]);close(newdesc[1]); //I don't need these descriptors anymore, as they must be redirected to the standard's input/output of the process they need.
}//End of function
*Edit:
I don't think it's good to close always the descriptors, even without creating anything, I saw I left them this way on this piece of code, but in order to make it work correctly we should only close the descriptors when created so an if would be needed on every close.
I'm working on a C terminal multiprocess application. The application is menu based, so the user have to choose from the possibilities to do the action. The menu is blocked with a getchar(). Let me show the codepart:
do
{
do
{
printf("\n\n---------------\nMenu\n\n");
printf("1. Option 1\n");
printf("2. Option 2\n");
printf("3. Option 3\n");
printf("4. Exit");
printf("\n\n---------------\n");
scanf("%d", &end);
int c = getchar();
if(end < 1 || end > 4)
{
printf("Try it again!!!\n\n");
}
}
while(end < 1 || end > 4);
}
while(end != 4);
So the user need to choose one of the options. But the problem is that the 2nd option needs to kick off a function in every 5 seconds in the background. One of the children will be handled by the function. So I've created an alarm() handler firstly with the simple signal() method. After that I'm realized that the getchar() I/O process is blocked by received signals. I've tried to create a new child which should handle the stdin processes, and send back the result in a pipe for the parent, but this was not worked too.
Let me share the current signal handling part for better understanding:
// Alarm handling
void CatchAlarm(int sig)
{
if(someCounts > 0)
{
DoSomething();
alarm(5);
}
}
Also the alarm binding:
struct sigaction alarmAction;
alarmAction.sa_handler = CatchAlarm;
sigemptyset(&alarmAction.sa_mask);
alarmAction.sa_flags = SA_RESTART;
sigaction(SIGALRM, &alarmAction, NULL);
My problem is that, I can't send the parent process to sleep, because the user have to be able to do other activities during the alarm is pending. When I get the SIGALRM, the full stdin reading process is going to crazy. Please help me what can I use to block the reading and waiting for user interaction instead of the getchar(), because I've already tried everything. Or if someone can help me how can I solve the issue I can appreciate that.
Of course, if you have further questions or concerns please let me know, and I'm going to update my question as soon as possible.
Thanks in advance
Just put an alarm(5); call before the getchar(); so the kernel is advised to send a SIGALRM signal to interrupt getchar(3). Then, you don't have to put any code inside the signal handler (but you do need the signal handler or the program will be killed, see alarm(2) and kill(2) for an explanation) You'll have to uninstall it after the getchar call either case or the signal handler will be called anyway after 5 seconds, but that's left as an exercise for the reader.
Note on notation
As standard in unix for a long time a reference like getchar(3) means the man page for getchar routine that is located in section 3 of the online unix reference manual. Section 2 is dedicated to system calls and section 3 to library calls historically.
I have written a simple C program that basically consists of an endless loop that counts upwards. During the loop, the user is asked for input- and here comes the tricky part: the loop should NOT be blocked while waiting on the user, but display his input as soon as he entered it:
int main(void){
int i;
char dec;
for(;;i++){
printf("%d\n", i);
sleep(5);
if(i==4 || i==8){
printf("Please enter Y or N\n");
dec = fgetc(stdin);
printf("%c\n", dec);
}
}
return 0;
}
I found a similiar question for Python here Python. So do I need to push the user interaction into a new thread with pthread or is there an easier option?
Thanks!
EDIT
int main(void){
int i=0;
char dec;
fd_set input_set;
for(;;i++){
printf("%d\n", i);
sleep(2);
if(i==4 || i==8){
FD_ZERO(&input_set ); /* Empty the FD Set */
FD_SET(0, &input_set); /* Listen to the input descriptor */
dec = select(1, &input_set, NULL, NULL, 0);
}
}
return 0;
}
What you want to do is only possible with system dependent libraries. For instance on Unix you would typically use ncurses to get from the user if they have pressed a button.
The reason it is system dependent is that asynchronous IO is not available for all file system streams. In particular User I/O blocks and that block is unavoidable.
If you are committed to having a multi-threaded program that still uses read/write system calls you would need to have two threads, one for I/O and one for everything else. On the everything else thread you could query some shared memory area and see if the I/O thread has written the correct type of data to this shared memory area.
If you are on linux only, check out this SO post : What are the differences between poll and select?
If you are on both and/or you already have pthreads, then use a separate thread.
If you are using Windows, maybe you can try to use keyboard hooks. See SetWindowsHookEx.
It will capture all the keyboard clicks with callback.
If you are usingLinux, maybe you can use this: Non-blocking keyboard read - C/C++